summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/Kconfig69
-rw-r--r--linux/drivers/media/video/Makefile15
-rw-r--r--linux/drivers/media/video/adv7170.c2
-rw-r--r--linux/drivers/media/video/adv7175.c2
-rw-r--r--linux/drivers/media/video/au0828/Kconfig13
-rw-r--r--linux/drivers/media/video/au0828/Makefile9
-rw-r--r--linux/drivers/media/video/au0828/au0828-cards.c181
-rw-r--r--linux/drivers/media/video/au0828/au0828-cards.h25
-rw-r--r--linux/drivers/media/video/au0828/au0828-core.c262
-rw-r--r--linux/drivers/media/video/au0828/au0828-dvb.c393
-rw-r--r--linux/drivers/media/video/au0828/au0828-i2c.c384
-rw-r--r--linux/drivers/media/video/au0828/au0828-reg.h38
-rw-r--r--linux/drivers/media/video/au0828/au0828.h132
-rw-r--r--linux/drivers/media/video/bt819.c2
-rw-r--r--linux/drivers/media/video/bt856.c2
-rw-r--r--linux/drivers/media/video/bt8xx/Kconfig1
-rw-r--r--linux/drivers/media/video/bt8xx/Makefile1
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-cards.c5
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c49
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-risc.c8
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-vbi.c6
-rw-r--r--linux/drivers/media/video/bt8xx/bttvp.h8
-rw-r--r--linux/drivers/media/video/btcx-risc.c2
-rw-r--r--linux/drivers/media/video/btcx-risc.h4
-rw-r--r--linux/drivers/media/video/c-qcam.c7
-rw-r--r--linux/drivers/media/video/cafe_ccic.c18
-rw-r--r--linux/drivers/media/video/compat_ioctl32.c1
-rw-r--r--linux/drivers/media/video/cpia.h4
-rw-r--r--linux/drivers/media/video/cpia2/cpia2_core.c12
-rw-r--r--linux/drivers/media/video/cpia_usb.c2
-rw-r--r--linux/drivers/media/video/cs5345.c14
-rw-r--r--linux/drivers/media/video/cs53l32a.c19
-rw-r--r--linux/drivers/media/video/cx18/Kconfig23
-rw-r--r--linux/drivers/media/video/cx18/Makefile11
-rw-r--r--linux/drivers/media/video/cx18/cx18-audio.c73
-rw-r--r--linux/drivers/media/video/cx18/cx18-audio.h26
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-audio.c361
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c888
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.h322
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-firmware.c120
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-vbi.c413
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.c281
-rw-r--r--linux/drivers/media/video/cx18/cx18-cards.h131
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.c306
-rw-r--r--linux/drivers/media/video/cx18/cx18-controls.h24
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.c962
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.h516
-rw-r--r--linux/drivers/media/video/cx18/cx18-dvb.c286
-rw-r--r--linux/drivers/media/video/cx18/cx18-dvb.h25
-rw-r--r--linux/drivers/media/video/cx18/cx18-fileops.c749
-rw-r--r--linux/drivers/media/video/cx18/cx18-fileops.h36
-rw-r--r--linux/drivers/media/video/cx18/cx18-firmware.c380
-rw-r--r--linux/drivers/media/video/cx18/cx18-firmware.h25
-rw-r--r--linux/drivers/media/video/cx18/cx18-gpio.c100
-rw-r--r--linux/drivers/media/video/cx18/cx18-gpio.h24
-rw-r--r--linux/drivers/media/video/cx18/cx18-i2c.c465
-rw-r--r--linux/drivers/media/video/cx18/cx18-i2c.h33
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.c878
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.h30
-rw-r--r--linux/drivers/media/video/cx18/cx18-irq.c181
-rw-r--r--linux/drivers/media/video/cx18/cx18-irq.h37
-rw-r--r--linux/drivers/media/video/cx18/cx18-mailbox.c372
-rw-r--r--linux/drivers/media/video/cx18/cx18-mailbox.h73
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.c272
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.h55
-rw-r--r--linux/drivers/media/video/cx18/cx18-scb.c121
-rw-r--r--linux/drivers/media/video/cx18/cx18-scb.h285
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c603
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.h33
-rw-r--r--linux/drivers/media/video/cx18/cx18-vbi.c208
-rw-r--r--linux/drivers/media/video/cx18/cx18-vbi.h26
-rw-r--r--linux/drivers/media/video/cx18/cx18-version.h34
-rw-r--r--linux/drivers/media/video/cx18/cx18-video.c45
-rw-r--r--linux/drivers/media/video/cx18/cx18-video.h22
-rw-r--r--linux/drivers/media/video/cx18/cx23418.h458
-rw-r--r--linux/drivers/media/video/cx23885/Kconfig16
-rw-r--r--linux/drivers/media/video/cx23885/Makefile3
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-417.c1772
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c166
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-core.c314
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c191
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-i2c.c44
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-video.c80
-rw-r--r--linux/drivers/media/video/cx23885/cx23885.h28
-rw-r--r--linux/drivers/media/video/cx25840/Kconfig1
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-core.c22
-rw-r--r--linux/drivers/media/video/cx88/Kconfig7
-rw-r--r--linux/drivers/media/video/cx88/Makefile1
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c6
-rw-r--r--linux/drivers/media/video/cx88/cx88-blackbird.c30
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c68
-rw-r--r--linux/drivers/media/video/cx88/cx88-core.c12
-rw-r--r--linux/drivers/media/video/cx88/cx88-dvb.c298
-rw-r--r--linux/drivers/media/video/cx88/cx88-i2c.c31
-rw-r--r--linux/drivers/media/video/cx88/cx88-mpeg.c16
-rw-r--r--linux/drivers/media/video/cx88/cx88-tvaudio.c24
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c24
-rw-r--r--linux/drivers/media/video/dpc7146.c2
-rw-r--r--linux/drivers/media/video/em28xx/Kconfig13
-rw-r--r--linux/drivers/media/video/em28xx/Makefile2
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-audio.c2
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c269
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c848
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c528
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c154
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-input.c28
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-reg.h88
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c1147
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h324
-rw-r--r--linux/drivers/media/video/et61x251/et61x251.h6
-rw-r--r--linux/drivers/media/video/et61x251/et61x251_core.c2
-rw-r--r--linux/drivers/media/video/ir-kbd-i2c.c24
-rw-r--r--linux/drivers/media/video/ivtv/Kconfig3
-rw-r--r--linux/drivers/media/video/ivtv/Makefile1
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-cards.c146
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-cards.h6
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-controls.c4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.c60
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-driver.h10
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-fileops.c12
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-gpio.c20
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-i2c.c29
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-ioctl.c62
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-ioctl.h6
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-irq.c12
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-mailbox.c11
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-queue.c14
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-streams.c50
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-streams.h2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-vbi.c3
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-version.h2
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-yuv.c8
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-yuv.h2
-rw-r--r--linux/drivers/media/video/ivtv/ivtvfb.c90
-rw-r--r--linux/drivers/media/video/m52790.c16
-rw-r--r--linux/drivers/media/video/meye.c1367
-rw-r--r--linux/drivers/media/video/msp3400-driver.c28
-rw-r--r--linux/drivers/media/video/mt20xx.c706
-rw-r--r--linux/drivers/media/video/mt20xx.h37
-rw-r--r--linux/drivers/media/video/mt9m001.c19
-rw-r--r--linux/drivers/media/video/mt9v022.c19
-rw-r--r--linux/drivers/media/video/mxb.c5
-rw-r--r--linux/drivers/media/video/ov511.c3
-rw-r--r--linux/drivers/media/video/ov511.h2
-rw-r--r--linux/drivers/media/video/ovcamchip/ovcamchip_priv.h4
-rw-r--r--linux/drivers/media/video/pvrusb2/Kconfig50
-rw-r--r--linux/drivers/media/video/pvrusb2/Makefile7
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-audio.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-audio.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-context.c292
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-context.h13
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c5
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c7
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-debug.h2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c25
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c253
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h36
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c438
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-dvb.h45
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c10
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h49
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h9
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c690
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h17
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-io.c33
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-io.h13
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-main.c17
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-std.c1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-std.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c511
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-util.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c124
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2.h1
-rw-r--r--linux/drivers/media/video/pwc/pwc-if.c13
-rw-r--r--linux/drivers/media/video/pwc/pwc-v4l.c4
-rw-r--r--linux/drivers/media/video/pxa_camera.c480
-rw-r--r--linux/drivers/media/video/saa7110.c4
-rw-r--r--linux/drivers/media/video/saa7111.c2
-rw-r--r--linux/drivers/media/video/saa7114.c2
-rw-r--r--linux/drivers/media/video/saa7115.c51
-rw-r--r--linux/drivers/media/video/saa7127.c16
-rw-r--r--linux/drivers/media/video/saa7134/Kconfig5
-rw-r--r--linux/drivers/media/video/saa7134/Makefile1
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-alsa.c4
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c336
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c6
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c159
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c19
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-i2c.c44
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-input.c14
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-reg.h1
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-tvaudio.c24
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-video.c48
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h1
-rw-r--r--linux/drivers/media/video/saa717x.c1547
-rw-r--r--linux/drivers/media/video/saa7185.c2
-rw-r--r--linux/drivers/media/video/se401.c6
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102.h6
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102_core.c2
-rw-r--r--linux/drivers/media/video/soc_camera.c28
-rw-r--r--linux/drivers/media/video/stk-webcam.c27
-rw-r--r--linux/drivers/media/video/stv680.c2
-rw-r--r--linux/drivers/media/video/tcm825x.c22
-rw-r--r--linux/drivers/media/video/tcm825x.h1
-rw-r--r--linux/drivers/media/video/tda8290.c833
-rw-r--r--linux/drivers/media/video/tda8290.h57
-rw-r--r--linux/drivers/media/video/tda9840.c6
-rw-r--r--linux/drivers/media/video/tda9887.c728
-rw-r--r--linux/drivers/media/video/tda9887.h38
-rw-r--r--linux/drivers/media/video/tea5761.c325
-rw-r--r--linux/drivers/media/video/tea5761.h47
-rw-r--r--linux/drivers/media/video/tea5767.c523
-rw-r--r--linux/drivers/media/video/tea5767.h66
-rw-r--r--linux/drivers/media/video/tea6415c.c6
-rw-r--r--linux/drivers/media/video/tea6420.c6
-rw-r--r--linux/drivers/media/video/tlv320aic23b.c15
-rw-r--r--linux/drivers/media/video/tuner-core.c292
-rw-r--r--linux/drivers/media/video/tuner-i2c.h173
-rw-r--r--linux/drivers/media/video/tuner-simple.c1136
-rw-r--r--linux/drivers/media/video/tuner-simple.h39
-rw-r--r--linux/drivers/media/video/tuner-types.c1653
-rw-r--r--linux/drivers/media/video/tuner-xc2028-types.h128
-rw-r--r--linux/drivers/media/video/tuner-xc2028.c1256
-rw-r--r--linux/drivers/media/video/tuner-xc2028.h63
-rw-r--r--linux/drivers/media/video/tvaudio.c21
-rw-r--r--linux/drivers/media/video/tveeprom.c10
-rw-r--r--linux/drivers/media/video/tvp5150.c4
-rw-r--r--linux/drivers/media/video/upd64031a.c15
-rw-r--r--linux/drivers/media/video/upd64083.c15
-rw-r--r--linux/drivers/media/video/usbvideo/ibmcam.c62
-rw-r--r--linux/drivers/media/video/usbvideo/konicawc.c2
-rw-r--r--linux/drivers/media/video/usbvideo/quickcam_messenger.c4
-rw-r--r--linux/drivers/media/video/usbvideo/usbvideo.c140
-rw-r--r--linux/drivers/media/video/usbvideo/vicam.c8
-rw-r--r--linux/drivers/media/video/usbvision/Makefile1
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-video.c18
-rw-r--r--linux/drivers/media/video/v4l2-common.c7
-rw-r--r--linux/drivers/media/video/videobuf-core.c75
-rw-r--r--linux/drivers/media/video/videobuf-dma-sg.c19
-rw-r--r--linux/drivers/media/video/videobuf-dvb.c16
-rw-r--r--linux/drivers/media/video/videobuf-vmalloc.c208
-rw-r--r--linux/drivers/media/video/videocodec.c113
-rw-r--r--linux/drivers/media/video/videodev.c367
-rw-r--r--linux/drivers/media/video/vino.c2
-rw-r--r--linux/drivers/media/video/vivi.c46
-rw-r--r--linux/drivers/media/video/vp27smpx.c17
-rw-r--r--linux/drivers/media/video/w9966.c2
-rw-r--r--linux/drivers/media/video/w9968cf.h6
-rw-r--r--linux/drivers/media/video/wm8739.c14
-rw-r--r--linux/drivers/media/video/wm8775.c14
-rw-r--r--linux/drivers/media/video/zc0301/zc0301.h6
-rw-r--r--linux/drivers/media/video/zc0301/zc0301_core.c2
-rw-r--r--linux/drivers/media/video/zoran.h20
-rw-r--r--linux/drivers/media/video/zoran_device.c4
-rw-r--r--linux/drivers/media/video/zoran_driver.c36
-rw-r--r--linux/drivers/media/video/zoran_procfs.c7
-rw-r--r--linux/drivers/media/video/zr364xx.c18
278 files changed, 23103 insertions, 12495 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index 31823b8f2..edd5a652d 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -1,4 +1,54 @@
#
+# Generic video config states
+#
+
+config VIDEO_V4L2
+ tristate
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON
+ default VIDEO_DEV && VIDEO_V4L2_COMMON
+
+config VIDEO_V4L1
+ tristate
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+ default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+
+config VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DMA_SG
+ depends on HAS_DMA
+ select VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_VMALLOC
+ select VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DVB
+ tristate
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
+
+config VIDEO_BTCX
+ tristate
+
+config VIDEO_IR_I2C
+ tristate
+
+config VIDEO_IR
+ tristate
+ depends on INPUT
+ select VIDEO_IR_I2C if I2C
+
+config VIDEO_TVEEPROM
+ tristate
+ depends on I2C
+
+config VIDEO_TUNER
+ tristate
+ depends on MEDIA_TUNER
+
+#
# Multimedia Video device configuration
#
@@ -270,6 +320,15 @@ config VIDEO_SAA711X
To compile this driver as a module, choose M here: the
module will be called saa7115.
+config VIDEO_SAA717X
+ tristate "Philips SAA7171/3/4 audio/video decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7171/3/4 audio/video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa717x.
+
config VIDEO_SAA7191
tristate "Philips SAA7191 video decoder"
depends on VIDEO_V4L1 && I2C
@@ -689,8 +748,12 @@ source "drivers/media/video/cx88/Kconfig"
source "drivers/media/video/cx23885/Kconfig"
+source "drivers/media/video/au0828/Kconfig"
+
source "drivers/media/video/ivtv/Kconfig"
+source "drivers/media/video/cx18/Kconfig"
+
config VIDEO_M32R_AR
tristate "AR devices"
depends on M32R && VIDEO_V4L1
@@ -840,7 +903,7 @@ endif # V4L_USB_DRIVERS
config SOC_CAMERA
tristate "SoC camera support"
- depends on VIDEO_V4L2
+ depends on VIDEO_V4L2 && HAS_DMA
select VIDEOBUF_DMA_SG
help
SoC Camera is a common API to several cameras, not connecting
@@ -849,7 +912,7 @@ config SOC_CAMERA
config SOC_CAMERA_MT9M001
tristate "mt9m001 support"
- depends on SOC_CAMERA
+ depends on SOC_CAMERA && I2C
select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
help
This driver supports MT9M001 cameras from Micron, monochrome
@@ -864,7 +927,7 @@ config MT9M001_PCA9536_SWITCH
config SOC_CAMERA_MT9V022
tristate "mt9v022 support"
- depends on SOC_CAMERA
+ depends on SOC_CAMERA && I2C
select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
help
This driver supports MT9V022 cameras from Micron
diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile
index 53d4dbf50..29139b53d 100644
--- a/linux/drivers/media/video/Makefile
+++ b/linux/drivers/media/video/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
obj-$(CONFIG_VIDEO_SAA7111) += saa7111.o
obj-$(CONFIG_VIDEO_SAA7114) += saa7114.o
obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
@@ -86,16 +87,6 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
-obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
-# tuner-types will be merged into tuner-simple, in the future
-obj-$(CONFIG_TUNER_SIMPLE) += tuner-types.o
-obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
-obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
-obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
-obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
-obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
-
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
@@ -134,6 +125,7 @@ obj-$(CONFIG_USB_VICAM) += usbvideo/
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+obj-$(CONFIG_VIDEO_CX18) += cx18/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
@@ -143,5 +135,8 @@ obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
+obj-$(CONFIG_VIDEO_AU0828) += au0828/
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/linux/drivers/media/video/adv7170.c b/linux/drivers/media/video/adv7170.c
index 0d15ce53d..54ef7aa63 100644
--- a/linux/drivers/media/video/adv7170.c
+++ b/linux/drivers/media/video/adv7170.c
@@ -409,7 +409,7 @@ adv7170_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/adv7175.c b/linux/drivers/media/video/adv7175.c
index 86345ba5c..b8618c021 100644
--- a/linux/drivers/media/video/adv7175.c
+++ b/linux/drivers/media/video/adv7175.c
@@ -427,7 +427,7 @@ adv7175_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/au0828/Kconfig b/linux/drivers/media/video/au0828/Kconfig
new file mode 100644
index 000000000..52b249158
--- /dev/null
+++ b/linux/drivers/media/video/au0828/Kconfig
@@ -0,0 +1,13 @@
+
+config VIDEO_AU0828
+ tristate "Auvitek AU0828 support"
+ depends on I2C && INPUT && DVB_CORE && USB
+ select I2C_ALGOBIT
+ select VIDEO_TVEEPROM
+ select DVB_AU8522 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ ---help---
+ This is a video4linux driver for Auvitek's USB device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called au0828
diff --git a/linux/drivers/media/video/au0828/Makefile b/linux/drivers/media/video/au0828/Makefile
new file mode 100644
index 000000000..cd2c58281
--- /dev/null
+++ b/linux/drivers/media/video/au0828/Makefile
@@ -0,0 +1,9 @@
+au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
+
+obj-$(CONFIG_VIDEO_AU0828) += au0828.o
+
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c
new file mode 100644
index 000000000..a2a698344
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-cards.c
@@ -0,0 +1,181 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "au0828.h"
+#include "au0828-cards.h"
+
+struct au0828_board au0828_boards[] = {
+ [AU0828_BOARD_UNKNOWN] = {
+ .name = "Unknown board",
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR850] = {
+ .name = "Hauppauge HVR850",
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
+ .name = "Hauppauge HVR950Q",
+ },
+ [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
+ .name = "DViCO FusionHDTV USB",
+ },
+};
+
+/* Tuner callback function for au0828 boards. Currently only needed
+ * for HVR1500Q, which has an xc5000 tuner.
+ */
+int au0828_tuner_callback(void *priv, int command, int arg)
+{
+ struct au0828_dev *dev = priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ switch (dev->board) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ if (command == 0) {
+ /* Tuner Reset Command from xc5000 */
+ /* Drive the tuner into reset and out */
+ au0828_clear(dev, REG_001, 2);
+ mdelay(200);
+ au0828_set(dev, REG_001, 2);
+ mdelay(50);
+ return 0;
+ } else {
+ printk(KERN_ERR
+ "%s(): Unknown command.\n", __func__);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ return 0; /* Should never be here */
+}
+
+static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
+{
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+
+ /* Make sure we support the board model */
+ switch (tv.model) {
+ case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+ break;
+ default:
+ printk(KERN_WARNING "%s: warning: "
+ "unknown hauppauge model #%d\n", __func__, tv.model);
+ break;
+ }
+
+ printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+ __func__, tv.model);
+}
+
+void au0828_card_setup(struct au0828_dev *dev)
+{
+ static u8 eeprom[256];
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (dev->i2c_rc == 0) {
+ dev->i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
+ }
+
+ switch (dev->board) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ if (dev->i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0xa0);
+ break;
+ }
+}
+
+/*
+ * The bridge has between 8 and 12 gpios.
+ * Regs 1 and 0 deal with output enables.
+ * Regs 3 and 2 deal with direction.
+ */
+void au0828_gpio_setup(struct au0828_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ switch (dev->board) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ /* GPIO's
+ * 4 - CS5340
+ * 5 - AU8522 Demodulator
+ * 6 - eeprom W/P
+ * 9 - XC5000 Tuner
+ */
+
+ /* Into reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0x88 | 0x20);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_000, 0x0);
+ msleep(100);
+
+ /* Out of reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_001, 0x02);
+ au0828_write(dev, REG_002, 0x88 | 0x20);
+ au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
+ msleep(250);
+ break;
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ /* GPIO's
+ * 6 - ?
+ * 8 - AU8522 Demodulator
+ * 9 - XC5000 Tuner
+ */
+
+ /* Into reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0xa0);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_000, 0x0);
+ msleep(100);
+
+ /* Out of reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0xa0);
+ au0828_write(dev, REG_001, 0x02);
+ au0828_write(dev, REG_000, 0xa0);
+ msleep(250);
+ break;
+ }
+}
+
+/* table of devices that work with this driver */
+struct usb_device_id au0828_usb_id_table [] = {
+ { USB_DEVICE(0x2040, 0x7200),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7240),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
+ { USB_DEVICE(0x0fe9, 0xd620),
+ .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
diff --git a/linux/drivers/media/video/au0828/au0828-cards.h b/linux/drivers/media/video/au0828/au0828-cards.h
new file mode 100644
index 000000000..e26f54a96
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-cards.h
@@ -0,0 +1,25 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define AU0828_BOARD_UNKNOWN 0
+#define AU0828_BOARD_HAUPPAUGE_HVR950Q 1
+#define AU0828_BOARD_HAUPPAUGE_HVR850 2
+#define AU0828_BOARD_DVICO_FUSIONHDTV7 3
diff --git a/linux/drivers/media/video/au0828/au0828-core.c b/linux/drivers/media/video/au0828/au0828-core.c
new file mode 100644
index 000000000..5642058ae
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-core.c
@@ -0,0 +1,262 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include "compat.h"
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+#include <linux/mutex.h>
+#endif
+
+#include "au0828.h"
+
+/*
+ * 1 = General debug messages
+ * 2 = USB handling
+ * 4 = I2C related
+ * 8 = Bridge related
+ */
+int au0828_debug;
+module_param_named(debug, au0828_debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+#define _AU0828_BULKPIPE 0x03
+#define _BULKPIPESIZE 0xffff
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size);
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size);
+
+/* USB Direction */
+#define CMD_REQUEST_IN 0x00
+#define CMD_REQUEST_OUT 0x01
+
+u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
+{
+ recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
+ dprintk(8, "%s(0x%x) = 0x%x\n", __func__, reg, dev->ctrlmsg[0]);
+ return dev->ctrlmsg[0];
+}
+
+u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
+{
+ dprintk(8, "%s(0x%x, 0x%x)\n", __func__, reg, val);
+ return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
+ dev->ctrlmsg, 0);
+}
+
+static void cmd_msg_dump(struct au0828_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < sizeof(dev->ctrlmsg); i += 16)
+ dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ __func__,
+ dev->ctrlmsg[i+0], dev->ctrlmsg[i+1],
+ dev->ctrlmsg[i+2], dev->ctrlmsg[i+3],
+ dev->ctrlmsg[i+4], dev->ctrlmsg[i+5],
+ dev->ctrlmsg[i+6], dev->ctrlmsg[i+7],
+ dev->ctrlmsg[i+8], dev->ctrlmsg[i+9],
+ dev->ctrlmsg[i+10], dev->ctrlmsg[i+11],
+ dev->ctrlmsg[i+12], dev->ctrlmsg[i+13],
+ dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]);
+}
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size)
+{
+ int status = -ENODEV;
+ mutex_lock(&dev->mutex);
+ if (dev->usbdev) {
+
+ /* cp must be memory that has been allocated by kmalloc */
+ status = usb_control_msg(dev->usbdev,
+ usb_sndctrlpipe(dev->usbdev, 0),
+ request,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ cp, size, 1000);
+
+ status = min(status, 0);
+
+ if (status < 0) {
+ printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+ __func__, status);
+ }
+
+ }
+ mutex_unlock(&dev->mutex);
+ return status;
+}
+
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size)
+{
+ int status = -ENODEV;
+ mutex_lock(&dev->mutex);
+ if (dev->usbdev) {
+
+ memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg));
+
+ /* cp must be memory that has been allocated by kmalloc */
+ status = usb_control_msg(dev->usbdev,
+ usb_rcvctrlpipe(dev->usbdev, 0),
+ request,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ cp, size, 1000);
+
+ status = min(status, 0);
+
+ if (status < 0) {
+ printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+ __func__, status);
+ } else
+ cmd_msg_dump(dev);
+ }
+ mutex_unlock(&dev->mutex);
+ return status;
+}
+
+static void au0828_usb_disconnect(struct usb_interface *interface)
+{
+ struct au0828_dev *dev = usb_get_intfdata(interface);
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Digital TV */
+ au0828_dvb_unregister(dev);
+
+ /* I2C */
+ au0828_i2c_unregister(dev);
+
+ usb_set_intfdata(interface, NULL);
+
+ mutex_lock(&dev->mutex);
+ dev->usbdev = NULL;
+ mutex_unlock(&dev->mutex);
+
+ kfree(dev);
+
+}
+
+static int au0828_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ int ifnum;
+ struct au0828_dev *dev;
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+
+ ifnum = interface->altsetting->desc.bInterfaceNumber;
+
+ if (ifnum != 0)
+ return -ENODEV;
+
+ dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
+ le16_to_cpu(usbdev->descriptor.idVendor),
+ le16_to_cpu(usbdev->descriptor.idProduct),
+ ifnum);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ mutex_init(&dev->mutex);
+ mutex_init(&dev->dvb.lock);
+ dev->usbdev = usbdev;
+ dev->board = id->driver_info;
+
+ usb_set_intfdata(interface, dev);
+
+ /* Power Up the bridge */
+ au0828_write(dev, REG_600, 1 << 4);
+
+ /* Bring up the GPIO's and supporting devices */
+ au0828_gpio_setup(dev);
+
+ /* I2C */
+ au0828_i2c_register(dev);
+
+ /* Setup */
+ au0828_card_setup(dev);
+
+ /* Digital TV */
+ au0828_dvb_register(dev);
+
+ printk(KERN_INFO "Registered device AU0828 [%s]\n",
+ au0828_boards[dev->board].name == NULL ? "Unset" :
+ au0828_boards[dev->board].name);
+
+ return 0;
+}
+
+static struct usb_driver au0828_usb_driver = {
+ .name = DRIVER_NAME,
+ .probe = au0828_usb_probe,
+ .disconnect = au0828_usb_disconnect,
+ .id_table = au0828_usb_id_table,
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
+ .owner = THIS_MODULE,
+#endif
+};
+
+static int __init au0828_init(void)
+{
+ int ret;
+
+ if (au0828_debug & 1)
+ printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+
+ if (au0828_debug & 2)
+ printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+
+ if (au0828_debug & 4)
+ printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+
+ if (au0828_debug & 8)
+ printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+ __func__);
+
+ printk(KERN_INFO "au0828 driver loaded\n");
+
+ ret = usb_register(&au0828_usb_driver);
+ if (ret)
+ printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+
+ return ret;
+}
+
+static void __exit au0828_exit(void)
+{
+ usb_deregister(&au0828_usb_driver);
+}
+
+module_init(au0828_init);
+module_exit(au0828_exit);
+
+MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c
new file mode 100644
index 000000000..709a703fe
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-dvb.c
@@ -0,0 +1,393 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <media/v4l2-common.h>
+#include "compat.h"
+
+#include "au0828.h"
+#include "au8522.h"
+#include "xc5000.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define _AU0828_BULKPIPE 0x83
+#define _BULKPIPESIZE 0xe522
+
+static struct au8522_config hauppauge_hvr950q_config = {
+ .demod_address = 0x8e >> 1,
+ .status_mode = AU8522_DEMODLOCKING,
+};
+
+static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
+ .i2c_address = 0x61,
+ .if_khz = 6000,
+ .tuner_callback = au0828_tuner_callback
+};
+
+/*-------------------------------------------------------------------*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void urb_completion(struct urb *purb, struct pt_regs *regs)
+#else
+static void urb_completion(struct urb *purb)
+#endif
+{
+ u8 *ptr;
+ struct au0828_dev *dev = purb->context;
+ int ptype = usb_pipetype(purb->pipe);
+
+ dprintk(2, "%s()\n", __func__);
+
+ if (!dev)
+ return;
+
+ if (dev->urb_streaming == 0)
+ return;
+
+ if (ptype != PIPE_BULK) {
+ printk(KERN_ERR "%s() Unsupported URB type %d\n",
+ __func__, ptype);
+ return;
+ }
+
+ ptr = (u8 *)purb->transfer_buffer;
+
+ /* Feed the transport payload into the kernel demux */
+ dvb_dmx_swfilter_packets(&dev->dvb.demux,
+ purb->transfer_buffer, purb->actual_length / 188);
+
+ /* Clean the buffer before we requeue */
+ memset(purb->transfer_buffer, 0, URB_BUFSIZE);
+
+ /* Requeue URB */
+ usb_submit_urb(purb, GFP_ATOMIC);
+}
+
+static int stop_urb_transfer(struct au0828_dev *dev)
+{
+ int i;
+
+ dprintk(2, "%s()\n", __func__);
+
+ for (i = 0; i < URB_COUNT; i++) {
+ usb_kill_urb(dev->urbs[i]);
+ kfree(dev->urbs[i]->transfer_buffer);
+ usb_free_urb(dev->urbs[i]);
+ }
+
+ dev->urb_streaming = 0;
+
+ return 0;
+}
+
+static int start_urb_transfer(struct au0828_dev *dev)
+{
+ struct urb *purb;
+ int i, ret = -ENOMEM;
+
+ dprintk(2, "%s()\n", __func__);
+
+ if (dev->urb_streaming) {
+ dprintk(2, "%s: iso xfer already running!\n", __func__);
+ return 0;
+ }
+
+ for (i = 0; i < URB_COUNT; i++) {
+
+ dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->urbs[i])
+ goto err;
+
+ purb = dev->urbs[i];
+
+ purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+ if (!purb->transfer_buffer) {
+ usb_free_urb(purb);
+ dev->urbs[i] = NULL;
+ goto err;
+ }
+
+ purb->status = -EINPROGRESS;
+ usb_fill_bulk_urb(purb,
+ dev->usbdev,
+ usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE),
+ purb->transfer_buffer,
+ URB_BUFSIZE,
+ urb_completion,
+ dev);
+
+ }
+
+ for (i = 0; i < URB_COUNT; i++) {
+ ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
+ if (ret != 0) {
+ stop_urb_transfer(dev);
+ printk(KERN_ERR "%s: failed urb submission, "
+ "err = %d\n", __func__, ret);
+ return ret;
+ }
+ }
+
+ dev->urb_streaming = 1;
+ ret = 0;
+
+err:
+ return ret;
+}
+
+static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret = 0;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ if (dvb) {
+ mutex_lock(&dvb->lock);
+ if (dvb->feeding++ == 0) {
+ /* Start transport */
+ au0828_write(dev, 0x608, 0x90);
+ au0828_write(dev, 0x609, 0x72);
+ au0828_write(dev, 0x60a, 0x71);
+ au0828_write(dev, 0x60b, 0x01);
+ ret = start_urb_transfer(dev);
+ }
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
+static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret = 0;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (dvb) {
+ mutex_lock(&dvb->lock);
+ if (--dvb->feeding == 0) {
+ /* Stop transport */
+ au0828_write(dev, 0x608, 0x00);
+ au0828_write(dev, 0x609, 0x00);
+ au0828_write(dev, 0x60a, 0x00);
+ au0828_write(dev, 0x60b, 0x00);
+ ret = stop_urb_transfer(dev);
+ }
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
+static int dvb_register(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+ int result;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* register adapter */
+ result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+ &dev->usbdev->dev, adapter_nr);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_register_adapter failed "
+ "(errno = %d)\n", DRIVER_NAME, result);
+ goto fail_adapter;
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+#else
+ dvb->adapter->priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(dvb->adapter, dvb->frontend);
+#endif
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_register_frontend failed "
+ "(errno = %d)\n", DRIVER_NAME, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dev;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = au0828_dvb_start_feed;
+ dvb->demux.stop_feed = au0828_dvb_stop_feed;
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+#else
+ result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
+#endif
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_ERR "%s: add_frontend failed "
+ "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ printk(KERN_ERR "%s: add_frontend failed "
+ "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#else
+ dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#endif
+ return 0;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_unregister_adapter(&dvb->adapter);
+#else
+ dvb_unregister_adapter(dvb->adapter);
+#endif
+fail_adapter:
+ return result;
+}
+
+void au0828_dvb_unregister(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (dvb->frontend == NULL)
+ return;
+
+ dvb_net_release(&dvb->net);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_unregister_adapter(&dvb->adapter);
+#else
+ dvb_unregister_adapter(dvb->adapter);
+#endif
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+int au0828_dvb_register(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* init frontend */
+ switch (dev->board) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ dvb->frontend = dvb_attach(au8522_attach,
+ &hauppauge_hvr950q_config,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL)
+ dvb_attach(xc5000_attach, dvb->frontend,
+ &dev->i2c_adap,
+ &hauppauge_hvr950q_tunerconfig, dev);
+ break;
+ default:
+ printk(KERN_WARNING "The frontend of your DVB/ATSC card "
+ "isn't supported yet\n");
+ break;
+ }
+ if (NULL == dvb->frontend) {
+ printk(KERN_ERR "%s() Frontend initialization failed\n",
+ __func__);
+ return -1;
+ }
+
+ /* register everything */
+ ret = dvb_register(dev);
+ if (ret < 0) {
+ if (dvb->frontend->ops.release)
+ dvb->frontend->ops.release(dvb->frontend);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/linux/drivers/media/video/au0828/au0828-i2c.c b/linux/drivers/media/video/au0828/au0828-i2c.c
new file mode 100644
index 000000000..b40a086e4
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-i2c.c
@@ -0,0 +1,384 @@
+/*
+ * Driver for the Auvitek AU0828 USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "compat.h"
+#include "au0828.h"
+
+#include <media/v4l2-common.h>
+
+static int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define I2C_WAIT_DELAY 512
+#define I2C_WAIT_RETRY 64
+
+static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x08 ? 0 : 1;
+}
+
+static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x02 ? 0 : 1;
+}
+
+static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_slave_did_read_ack(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x01 ? 0 : 1;
+}
+
+static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_is_read_busy(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x04 ? 1 : 0;
+}
+
+static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (i2c_is_write_done(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x10 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_is_busy(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int joined_rlen)
+{
+ int i, strobe = 0;
+ struct au0828_dev *dev = i2c_adap->algo_data;
+
+ dprintk(4, "%s()\n", __func__);
+
+ au0828_write(dev, REG_2FF, 0x01);
+ au0828_write(dev, REG_202, 0x07);
+
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, REG_203, msg->addr << 1);
+
+ dprintk(4, "SEND: %02x\n", msg->addr);
+
+ for (i = 0; i < msg->len;) {
+
+ dprintk(4, " %02x\n", msg->buf[i]);
+
+ au0828_write(dev, REG_205, msg->buf[i]);
+
+ strobe++;
+ i++;
+
+ if ((strobe >= 4) || (i >= msg->len)) {
+
+ /* Strobe the byte into the bus */
+ if (i < msg->len)
+ au0828_write(dev, REG_200, 0x41);
+ else
+ au0828_write(dev, REG_200, 0x01);
+
+ /* Reset strobe trigger */
+ strobe = 0;
+
+ if (!i2c_wait_write_done(i2c_adap))
+ return -EIO;
+
+ }
+
+ }
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+
+ dprintk(4, "\n");
+
+ return msg->len;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int joined)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ int i;
+
+ dprintk(4, "%s()\n", __func__);
+
+ au0828_write(dev, REG_2FF, 0x01);
+ au0828_write(dev, REG_202, 0x07);
+
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, REG_203, msg->addr << 1);
+
+ dprintk(4, " RECV:\n");
+
+ /* Deal with i2c_scan */
+ if (msg->len == 0) {
+ au0828_write(dev, REG_200, 0x20);
+ if (i2c_wait_read_ack(i2c_adap))
+ return -EIO;
+ return 0;
+ }
+
+ for (i = 0; i < msg->len;) {
+
+ i++;
+
+ if (i < msg->len)
+ au0828_write(dev, REG_200, 0x60);
+ else
+ au0828_write(dev, REG_200, 0x20);
+
+ if (!i2c_wait_read_done(i2c_adap))
+ return -EIO;
+
+ msg->buf[i-1] = au0828_read(dev, REG_209) & 0xff;
+
+ dprintk(4, " %02x\n", msg->buf[i-1]);
+ }
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+
+ dprintk(4, "\n");
+
+ return msg->len;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ int i, retval = 0;
+
+ dprintk(4, "%s(num = %d)\n", __func__, num);
+
+ for (i = 0; i < num; i++) {
+ dprintk(4, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
+ __func__, num, msgs[i].addr, msgs[i].len);
+ if (msgs[i].flags & I2C_M_RD) {
+ /* read */
+ retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+ } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+ msgs[i].addr == msgs[i + 1].addr) {
+ /* write then read from same address */
+ retval = i2c_sendbytes(i2c_adap, &msgs[i],
+ msgs[i + 1].len);
+ if (retval < 0)
+ goto err;
+ i++;
+ retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+ } else {
+ /* write */
+ retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+ }
+ if (retval < 0)
+ goto err;
+ }
+ return num;
+
+err:
+ return retval;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+ dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+ client->driver->driver.name, client->addr, client->name);
+
+ if (!client->driver->command)
+ return 0;
+
+ return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+ dprintk(1, "i2c detach [client=%s]\n", client->name);
+
+ return 0;
+}
+
+void au0828_call_i2c_clients(struct au0828_dev *dev,
+ unsigned int cmd, void *arg)
+{
+ if (dev->i2c_rc != 0)
+ return;
+
+ i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+static u32 au0828_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au0828_i2c_algo_template = {
+ .master_xfer = i2c_xfer,
+ .functionality = au0828_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter au0828_i2c_adap_template = {
+ .name = DRIVER_NAME,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ .owner = THIS_MODULE,
+#endif
+ .id = I2C_HW_B_AU0828,
+ .algo = &au0828_i2c_algo_template,
+ .class = I2C_CLASS_TV_ANALOG,
+ .client_register = attach_inform,
+ .client_unregister = detach_inform,
+};
+
+static struct i2c_client au0828_i2c_client_template = {
+ .name = "au0828 internal",
+};
+
+static char *i2c_devs[128] = {
+ [0x8e >> 1] = "au8522",
+ [0xa0 >> 1] = "eeprom",
+ [0xc2 >> 1] = "tuner/xc5000",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+ unsigned char buf;
+ int i, rc;
+
+ for (i = 0; i < 128; i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c, &buf, 0);
+ if (rc < 0)
+ continue;
+ printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n",
+ name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+}
+
+/* init + register i2c algo-bit adapter */
+int au0828_i2c_register(struct au0828_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ memcpy(&dev->i2c_adap, &au0828_i2c_adap_template,
+ sizeof(dev->i2c_adap));
+ memcpy(&dev->i2c_algo, &au0828_i2c_algo_template,
+ sizeof(dev->i2c_algo));
+ memcpy(&dev->i2c_client, &au0828_i2c_client_template,
+ sizeof(dev->i2c_client));
+
+ dev->i2c_adap.dev.parent = &dev->usbdev->dev;
+
+ strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+ sizeof(dev->i2c_adap.name));
+
+ dev->i2c_algo.data = dev;
+ dev->i2c_adap.algo_data = dev;
+ i2c_set_adapdata(&dev->i2c_adap, dev);
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client.adapter = &dev->i2c_adap;
+
+ if (0 == dev->i2c_rc) {
+ printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+ if (i2c_scan)
+ do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+ } else
+ printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+
+ return dev->i2c_rc;
+}
+
+int au0828_i2c_unregister(struct au0828_dev *dev)
+{
+ i2c_del_adapter(&dev->i2c_adap);
+ return 0;
+}
+
diff --git a/linux/drivers/media/video/au0828/au0828-reg.h b/linux/drivers/media/video/au0828/au0828-reg.h
new file mode 100644
index 000000000..398275508
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-reg.h
@@ -0,0 +1,38 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* We'll start to rename these registers once we have a better
+ * understanding of their meaning.
+ */
+#define REG_000 0x000
+#define REG_001 0x001
+#define REG_002 0x002
+#define REG_003 0x003
+
+#define REG_200 0x200
+#define REG_201 0x201
+#define REG_202 0x202
+#define REG_203 0x203
+#define REG_205 0x205
+#define REG_209 0x209
+#define REG_2FF 0x2ff
+
+#define REG_600 0x600
diff --git a/linux/drivers/media/video/au0828/au0828.h b/linux/drivers/media/video/au0828/au0828.h
new file mode 100644
index 000000000..b00d8cda5
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828.h
@@ -0,0 +1,132 @@
+/*
+ * Driver for the Auvitek AU0828 USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <media/tveeprom.h>
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#include "au0828-reg.h"
+#include "au0828-cards.h"
+
+#define DRIVER_NAME "au0828"
+#define URB_COUNT 16
+#define URB_BUFSIZE (0xe522)
+
+struct au0828_board {
+ char *name;
+};
+
+struct au0828_dvb {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex lock;
+#else
+ struct semaphore lock;
+#endif
+ struct dvb_adapter adapter;
+ struct dvb_frontend *frontend;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net net;
+ int feeding;
+};
+
+struct au0828_dev {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex mutex;
+#else
+ struct semaphore mutex;
+#endif
+ struct usb_device *usbdev;
+ int board;
+ u8 ctrlmsg[64];
+
+ /* I2C */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_rc;
+
+ /* Digital */
+ struct au0828_dvb dvb;
+
+ /* USB / URB Related */
+ int urb_streaming;
+ struct urb *urbs[URB_COUNT];
+
+};
+
+struct au0828_buff {
+ struct au0828_dev *dev;
+ struct urb *purb;
+ struct list_head buff_list;
+};
+
+/* ----------------------------------------------------------- */
+#define au0828_read(dev, reg) au0828_readreg(dev, reg)
+#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
+#define au0828_andor(dev, reg, mask, value) \
+ au0828_writereg(dev, reg, \
+ (au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask)))
+
+#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit))
+#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0)
+
+/* ----------------------------------------------------------- */
+/* au0828-core.c */
+extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
+extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
+extern int au0828_debug;
+
+/* ----------------------------------------------------------- */
+/* au0828-cards.c */
+extern struct au0828_board au0828_boards[];
+extern struct usb_device_id au0828_usb_id_table[];
+extern void au0828_gpio_setup(struct au0828_dev *dev);
+extern int au0828_tuner_callback(void *priv, int command, int arg);
+extern void au0828_card_setup(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-i2c.c */
+extern int au0828_i2c_register(struct au0828_dev *dev);
+extern int au0828_i2c_unregister(struct au0828_dev *dev);
+extern void au0828_call_i2c_clients(struct au0828_dev *dev,
+ unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------- */
+/* au0828-dvb.c */
+extern int au0828_dvb_register(struct au0828_dev *dev);
+extern void au0828_dvb_unregister(struct au0828_dev *dev);
+
+#define dprintk(level, fmt, arg...)\
+ do { if (au0828_debug & level)\
+ printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+ } while (0)
diff --git a/linux/drivers/media/video/bt819.c b/linux/drivers/media/video/bt819.c
index 9264e2cff..402bccaf7 100644
--- a/linux/drivers/media/video/bt819.c
+++ b/linux/drivers/media/video/bt819.c
@@ -525,7 +525,7 @@ bt819_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/bt856.c b/linux/drivers/media/video/bt856.c
index 7abfad9a4..50ca987ad 100644
--- a/linux/drivers/media/video/bt856.c
+++ b/linux/drivers/media/video/bt856.c
@@ -312,7 +312,7 @@ bt856_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/bt8xx/Kconfig b/linux/drivers/media/video/bt8xx/Kconfig
index cfc822bb5..24a34fc1f 100644
--- a/linux/drivers/media/video/bt8xx/Kconfig
+++ b/linux/drivers/media/video/bt8xx/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_BT848
tristate "BT848 Video For Linux"
depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
+ depends on HOTPLUG # due to FW_LOADER
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
diff --git a/linux/drivers/media/video/bt8xx/Makefile b/linux/drivers/media/video/bt8xx/Makefile
index 924d216d9..e415f6fc4 100644
--- a/linux/drivers/media/video/bt8xx/Makefile
+++ b/linux/drivers/media/video/bt8xx/Makefile
@@ -9,4 +9,5 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
obj-$(CONFIG_VIDEO_BT848) += bttv.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c
index 177b75ebc..0e6771643 100644
--- a/linux/drivers/media/video/bt8xx/bttv-cards.c
+++ b/linux/drivers/media/video/bt8xx/bttv-cards.c
@@ -35,6 +35,7 @@
#include <net/checksum.h>
#include "compat.h"
+#include <asm/unaligned.h>
#include <asm/io.h>
#include "bttvp.h"
@@ -3922,7 +3923,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
ee += i;
/* found a valid descriptor */
- type = be16_to_cpup((u16*)(ee+4));
+ type = get_unaligned_be16((__be16 *)(ee+4));
switch(type) {
/* 848 based */
@@ -3982,7 +3983,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
btv->c.nr, type);
break;
}
- serial = be32_to_cpup((u32*)(ee+6));
+ serial = get_unaligned_be32((__be32 *)(ee+6));
}
printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n",
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index c1173a94a..bb9ad09f8 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -2489,7 +2489,7 @@ pix_format_set_size (struct v4l2_pix_format * f,
}
}
-static int bttv_g_fmt_cap(struct file *file, void *priv,
+static int bttv_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct bttv_fh *fh = priv;
@@ -2502,7 +2502,7 @@ static int bttv_g_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int bttv_g_fmt_overlay(struct file *file, void *priv,
+static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_format *f)
{
struct bttv_fh *fh = priv;
@@ -2513,7 +2513,7 @@ static int bttv_g_fmt_overlay(struct file *file, void *priv,
return 0;
}
-static int bttv_try_fmt_cap(struct file *file, void *priv,
+static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
const struct bttv_format *fmt;
@@ -2573,7 +2573,7 @@ static int bttv_try_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int bttv_try_fmt_overlay(struct file *file, void *priv,
+static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_format *f)
{
struct bttv_fh *fh = priv;
@@ -2583,7 +2583,7 @@ static int bttv_try_fmt_overlay(struct file *file, void *priv,
/* adjust_crop */ 0);
}
-static int bttv_s_fmt_cap(struct file *file, void *priv,
+static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
int retval;
@@ -2597,7 +2597,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv,
if (0 != retval)
return retval;
- retval = bttv_try_fmt_cap(file, priv, f);
+ retval = bttv_try_fmt_vid_cap(file, priv, f);
if (0 != retval)
return retval;
@@ -2632,7 +2632,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int bttv_s_fmt_overlay(struct file *file, void *priv,
+static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_format *f)
{
struct bttv_fh *fh = priv;
@@ -2654,7 +2654,7 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
struct bttv_fh *fh = priv;
mutex_lock(&fh->cap.vb_lock);
- retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
+ retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
V4L2_MEMORY_MMAP);
if (retval < 0) {
mutex_unlock(&fh->cap.vb_lock);
@@ -2702,7 +2702,7 @@ static int bttv_querycap(struct file *file, void *priv,
return 0;
}
-static int bttv_enum_fmt_vbi(struct file *file, void *priv,
+static int bttv_enum_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (0 != f->index)
@@ -2733,7 +2733,7 @@ static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
return i;
}
-static int bttv_enum_fmt_cap(struct file *file, void *priv,
+static int bttv_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
int rc = bttv_enum_fmt_cap_ovr(f);
@@ -2744,7 +2744,7 @@ static int bttv_enum_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int bttv_enum_fmt_overlay(struct file *file, void *priv,
+static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
int rc;
@@ -3405,18 +3405,18 @@ static struct video_device bttv_video_template =
.fops = &bttv_fops,
.minor = -1,
.vidioc_querycap = bttv_querycap,
- .vidioc_enum_fmt_cap = bttv_enum_fmt_cap,
- .vidioc_g_fmt_cap = bttv_g_fmt_cap,
- .vidioc_try_fmt_cap = bttv_try_fmt_cap,
- .vidioc_s_fmt_cap = bttv_s_fmt_cap,
- .vidioc_enum_fmt_overlay = bttv_enum_fmt_overlay,
- .vidioc_g_fmt_overlay = bttv_g_fmt_overlay,
- .vidioc_try_fmt_overlay = bttv_try_fmt_overlay,
- .vidioc_s_fmt_overlay = bttv_s_fmt_overlay,
- .vidioc_enum_fmt_vbi = bttv_enum_fmt_vbi,
- .vidioc_g_fmt_vbi = bttv_g_fmt_vbi,
- .vidioc_try_fmt_vbi = bttv_try_fmt_vbi,
- .vidioc_s_fmt_vbi = bttv_s_fmt_vbi,
+ .vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay,
+ .vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay,
+ .vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay,
+ .vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay,
+ .vidioc_enum_fmt_vbi_cap = bttv_enum_fmt_vbi_cap,
+ .vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap,
.vidioc_g_audio = bttv_g_audio,
.vidioc_s_audio = bttv_s_audio,
.vidioc_cropcap = bttv_cropcap,
@@ -3506,6 +3506,9 @@ static int radio_release(struct inode *inode, struct file *file)
struct bttv *btv = fh->btv;
struct rds_command cmd;
+ file->private_data = NULL;
+ kfree(fh);
+
btv->radio_user--;
bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
diff --git a/linux/drivers/media/video/bt8xx/bttv-risc.c b/linux/drivers/media/video/bt8xx/bttv-risc.c
index a064f4ee9..a8c98e52c 100644
--- a/linux/drivers/media/video/bt8xx/bttv-risc.c
+++ b/linux/drivers/media/video/bt8xx/bttv-risc.c
@@ -48,7 +48,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
{
u32 instructions,line,todo;
struct scatterlist *sg;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -128,7 +128,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
unsigned int cpadding)
{
unsigned int instructions,line,todo,ylen,chroma;
- u32 *rp,ri;
+ __le32 *rp;
+ u32 ri;
struct scatterlist *ysg;
struct scatterlist *usg;
struct scatterlist *vsg;
@@ -244,7 +245,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
{
int dwords,rc,line,maxy,start,end,skip,nskips;
struct btcx_skiplist *skips;
- u32 *rp,ri,ra;
+ __le32 *rp;
+ u32 ri,ra;
u32 addr;
/* skip list for window clipping */
diff --git a/linux/drivers/media/video/bt8xx/bttv-vbi.c b/linux/drivers/media/video/bt8xx/bttv-vbi.c
index bfdbc469e..68f28e5fa 100644
--- a/linux/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/linux/drivers/media/video/bt8xx/bttv-vbi.c
@@ -303,7 +303,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
return 0;
}
-int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
@@ -321,7 +321,7 @@ int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
}
-int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
@@ -369,7 +369,7 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
}
-int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
+int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt)
{
struct bttv_fh *fh = f;
const struct bttv_tvnorm *tvnorm;
diff --git a/linux/drivers/media/video/bt8xx/bttvp.h b/linux/drivers/media/video/bt8xx/bttvp.h
index e9219458e..9fd8eeddf 100644
--- a/linux/drivers/media/video/bt8xx/bttvp.h
+++ b/linux/drivers/media/video/bt8xx/bttvp.h
@@ -90,8 +90,6 @@
/* Limits scaled width, which must be a multiple of 4. */
#define MAX_HACTIVE (0x3FF & -4)
-#define clamp(x, low, high) min (max (low, x), high)
-
#define BTTV_NORMS (\
V4L2_STD_PAL | V4L2_STD_PAL_N | \
V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
@@ -265,9 +263,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
-int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
-int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
-int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
extern struct videobuf_queue_ops bttv_vbi_qops;
diff --git a/linux/drivers/media/video/btcx-risc.c b/linux/drivers/media/video/btcx-risc.c
index 2d2ad58b4..e0e1158ce 100644
--- a/linux/drivers/media/video/btcx-risc.c
+++ b/linux/drivers/media/video/btcx-risc.c
@@ -64,7 +64,7 @@ int btcx_riscmem_alloc(struct pci_dev *pci,
struct btcx_riscmem *risc,
unsigned int size)
{
- u32 *cpu;
+ __le32 *cpu;
dma_addr_t dma;
if (NULL != risc->cpu && risc->size < size)
diff --git a/linux/drivers/media/video/btcx-risc.h b/linux/drivers/media/video/btcx-risc.h
index 503e6c6d7..861bc8112 100644
--- a/linux/drivers/media/video/btcx-risc.h
+++ b/linux/drivers/media/video/btcx-risc.h
@@ -2,8 +2,8 @@
*/
struct btcx_riscmem {
unsigned int size;
- u32 *cpu;
- u32 *jmp;
+ __le32 *cpu;
+ __le32 *jmp;
dma_addr_t dma;
};
diff --git a/linux/drivers/media/video/c-qcam.c b/linux/drivers/media/video/c-qcam.c
index 479ef617b..a5f5b8a4a 100644
--- a/linux/drivers/media/video/c-qcam.c
+++ b/linux/drivers/media/video/c-qcam.c
@@ -39,6 +39,7 @@
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
#include <linux/mutex.h>
#endif
+#include <linux/jiffies.h>
#include <asm/uaccess.h>
@@ -102,7 +103,8 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
+ for (oldjiffies = jiffies;
+ time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
if (qcam_ready1(qcam) == value)
return 0;
@@ -127,7 +129,8 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
+ for (oldjiffies = jiffies;
+ time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
if (qcam_ready2(qcam) == value)
return 0;
diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c
index 56409d585..b75c151cc 100644
--- a/linux/drivers/media/video/cafe_ccic.c
+++ b/linux/drivers/media/video/cafe_ccic.c
@@ -1600,7 +1600,7 @@ static struct v4l2_pix_format cafe_def_pix_format = {
.sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
};
-static int cafe_vidioc_enum_fmt_cap(struct file *filp,
+static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_fmtdesc *fmt)
{
struct cafe_camera *cam = priv;
@@ -1615,7 +1615,7 @@ static int cafe_vidioc_enum_fmt_cap(struct file *filp,
}
-static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
+static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
struct cafe_camera *cam = priv;
@@ -1627,7 +1627,7 @@ static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
return ret;
}
-static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
+static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
struct cafe_camera *cam = priv;
@@ -1642,7 +1642,7 @@ static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
/*
* See if the formatting works in principle.
*/
- ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);
+ ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt);
if (ret)
return ret;
/*
@@ -1677,7 +1677,7 @@ static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
* The V4l2 spec wants us to be smarter, and actually get this from
* the camera (and not mess with it at open time). Someday.
*/
-static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,
+static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *f)
{
struct cafe_camera *cam = priv;
@@ -1787,10 +1787,10 @@ static struct video_device cafe_v4l_template = {
.release = cafe_v4l_dev_release,
.vidioc_querycap = cafe_vidioc_querycap,
- .vidioc_enum_fmt_cap = cafe_vidioc_enum_fmt_cap,
- .vidioc_try_fmt_cap = cafe_vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = cafe_vidioc_s_fmt_cap,
- .vidioc_g_fmt_cap = cafe_vidioc_g_fmt_cap,
+ .vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = cafe_vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = cafe_vidioc_g_fmt_vid_cap,
.vidioc_enum_input = cafe_vidioc_enum_input,
.vidioc_g_input = cafe_vidioc_g_input,
.vidioc_s_input = cafe_vidioc_s_input,
diff --git a/linux/drivers/media/video/compat_ioctl32.c b/linux/drivers/media/video/compat_ioctl32.c
index c1ca880d0..6b405e75c 100644
--- a/linux/drivers/media/video/compat_ioctl32.c
+++ b/linux/drivers/media/video/compat_ioctl32.c
@@ -950,6 +950,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_G_INPUT32:
case VIDIOC_S_INPUT32:
case VIDIOC_TRY_FMT32:
+ case VIDIOC_S_HW_FREQ_SEEK:
ret = do_video_ioctl(file, cmd, arg);
break;
diff --git a/linux/drivers/media/video/cpia.h b/linux/drivers/media/video/cpia.h
index 107234853..d579b5edb 100644
--- a/linux/drivers/media/video/cpia.h
+++ b/linux/drivers/media/video/cpia.h
@@ -423,11 +423,11 @@ void cpia_unregister_camera(struct cam_data *cam);
/* ErrorCode */
#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */
#define ALOG(fmt,args...) printk(fmt, ##args)
-#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __FUNCTION__ , __LINE__ , ##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __func__ , __LINE__ , ##args)
#ifdef _CPIA_DEBUG_
#define ADBG(fmt,args...) printk(fmt, jiffies, ##args)
-#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __FUNCTION__, __LINE__ , ##args)
+#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __func__, __LINE__ , ##args)
#else
#define DBG(fmn,args...) do {} while(0)
#endif
diff --git a/linux/drivers/media/video/cpia2/cpia2_core.c b/linux/drivers/media/video/cpia2/cpia2_core.c
index a439a56c3..c8b9fdb70 100644
--- a/linux/drivers/media/video/cpia2/cpia2_core.c
+++ b/linux/drivers/media/video/cpia2/cpia2_core.c
@@ -570,7 +570,7 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
block_name[block_index]);
break;
default:
- LOG("%s: invalid request mode\n",__FUNCTION__);
+ LOG("%s: invalid request mode\n",__func__);
return -EINVAL;
}
@@ -952,7 +952,7 @@ static int set_default_user_mode(struct camera_data *cam)
frame_rate = CPIA2_VP_FRAMERATE_30;
break;
default:
- LOG("%s: Invalid sensor flag value 0x%0X\n",__FUNCTION__,
+ LOG("%s: Invalid sensor flag value 0x%0X\n",__func__,
cam->params.version.sensor_flags);
return -EINVAL;
}
@@ -2356,12 +2356,12 @@ long cpia2_read(struct camera_data *cam,
}
if (!buf) {
- ERR("%s: buffer NULL\n",__FUNCTION__);
+ ERR("%s: buffer NULL\n",__func__);
return -EINVAL;
}
if (!cam) {
- ERR("%s: Internal error, camera_data NULL!\n",__FUNCTION__);
+ ERR("%s: Internal error, camera_data NULL!\n",__func__);
return -EINVAL;
}
@@ -2370,7 +2370,7 @@ long cpia2_read(struct camera_data *cam,
return -ERESTARTSYS;
if (!cam->present) {
- LOG("%s: camera removed\n",__FUNCTION__);
+ LOG("%s: camera removed\n",__func__);
mutex_unlock(&cam->busy_lock);
return 0; /* EOF */
}
@@ -2434,7 +2434,7 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
unsigned int status=0;
if(!cam) {
- ERR("%s: Internal error, camera_data not found!\n",__FUNCTION__);
+ ERR("%s: Internal error, camera_data not found!\n",__func__);
return POLLERR;
}
diff --git a/linux/drivers/media/video/cpia_usb.c b/linux/drivers/media/video/cpia_usb.c
index 0d974be34..781999632 100644
--- a/linux/drivers/media/video/cpia_usb.c
+++ b/linux/drivers/media/video/cpia_usb.c
@@ -174,7 +174,7 @@ static void cpia_usb_complete(struct urb *urb)
/* resubmit */
urb->dev = ucpia->dev;
if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
- printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __FUNCTION__, i);
+ printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __func__, i);
}
static int cpia_usb_open(void *privdata)
diff --git a/linux/drivers/media/video/cs5345.c b/linux/drivers/media/video/cs5345.c
index 0377a24c6..d0bdc009d 100644
--- a/linux/drivers/media/video/cs5345.c
+++ b/linux/drivers/media/video/cs5345.c
@@ -156,7 +156,8 @@ static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
/* ----------------------------------------------------------------------- */
-static int cs5345_probe(struct i2c_client *client)
+static int cs5345_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -173,11 +174,22 @@ static int cs5345_probe(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id cs5345_id[] = {
+ { "cs5345", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs5345_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cs5345",
.driverid = I2C_DRIVERID_CS5345,
.command = cs5345_command,
.probe = cs5345_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = cs5345_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/cs53l32a.c b/linux/drivers/media/video/cs53l32a.c
index fe92723f1..7c0761e21 100644
--- a/linux/drivers/media/video/cs53l32a.c
+++ b/linux/drivers/media/video/cs53l32a.c
@@ -147,7 +147,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int cs53l32a_probe(struct i2c_client *client)
+static int cs53l32a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int i;
@@ -155,7 +156,12 @@ static int cs53l32a_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
+#else
+ if (!id)
+ strlcpy(client->name, "cs53l32a", sizeof(client->name));
+#endif
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -186,11 +192,22 @@ static int cs53l32a_probe(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id cs53l32a_id[] = {
+ { "cs53l32a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cs53l32a",
.driverid = I2C_DRIVERID_CS53L32A,
.command = cs53l32a_command,
.probe = cs53l32a_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = cs53l32a_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/cx18/Kconfig b/linux/drivers/media/video/cx18/Kconfig
new file mode 100644
index 000000000..5f9426905
--- /dev/null
+++ b/linux/drivers/media/video/cx18/Kconfig
@@ -0,0 +1,23 @@
+config VIDEO_CX18
+ tristate "Conexant cx23418 MPEG encoder support"
+ depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
+ depends on INPUT # due to VIDEO_IR
+ depends on HOTPLUG # due to FW_LOADER
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_IR
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
+ select VIDEO_CS5345
+ select DVB_S5H1409
+ select MEDIA_TUNER_MXL5005S
+ ---help---
+ This is a video4linux driver for Conexant cx23418 based
+ PCI combo video recorder devices.
+
+ This is used in devices such as the Hauppauge HVR-1600
+ cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx18.
diff --git a/linux/drivers/media/video/cx18/Makefile b/linux/drivers/media/video/cx18/Makefile
new file mode 100644
index 000000000..b23d2e261
--- /dev/null
+++ b/linux/drivers/media/video/cx18/Makefile
@@ -0,0 +1,11 @@
+cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \
+ cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
+ cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
+ cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
+ cx18-dvb.o
+
+obj-$(CONFIG_VIDEO_CX18) += cx18.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/linux/drivers/media/video/cx18/cx18-audio.c b/linux/drivers/media/video/cx18/cx18-audio.c
new file mode 100644
index 000000000..1adc404d9
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-audio.c
@@ -0,0 +1,73 @@
+/*
+ * cx18 audio-related functions
+ *
+ * Derived from ivtv-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-i2c.h"
+#include "cx18-cards.h"
+#include "cx18-audio.h"
+
+/* Selects the audio input and output according to the current
+ settings. */
+int cx18_audio_set_io(struct cx18 *cx)
+{
+ struct v4l2_routing route;
+ u32 audio_input;
+ int mux_input;
+
+ /* Determine which input to use */
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ audio_input = cx->card->radio_input.audio_input;
+ mux_input = cx->card->radio_input.muxer_input;
+ } else {
+ audio_input =
+ cx->card->audio_inputs[cx->audio_input].audio_input;
+ mux_input =
+ cx->card->audio_inputs[cx->audio_input].muxer_input;
+ }
+
+ /* handle muxer chips */
+ route.input = mux_input;
+ route.output = 0;
+ cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+ route.input = audio_input;
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+ VIDIOC_INT_S_AUDIO_ROUTING, &route);
+}
+
+void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
+{
+ cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+ VIDIOC_INT_S_AUDIO_ROUTING, route);
+}
+
+void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq)
+{
+ static u32 freqs[3] = { 44100, 48000, 32000 };
+
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (freq > 2)
+ return;
+ cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
+}
diff --git a/linux/drivers/media/video/cx18/cx18-audio.h b/linux/drivers/media/video/cx18/cx18-audio.h
new file mode 100644
index 000000000..cb569a693
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-audio.h
@@ -0,0 +1,26 @@
+/*
+ * cx18 audio-related functions
+ *
+ * Derived from ivtv-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_audio_set_io(struct cx18 *cx);
+void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route);
+void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq);
diff --git a/linux/drivers/media/video/cx18/cx18-av-audio.c b/linux/drivers/media/video/cx18/cx18-av-audio.c
new file mode 100644
index 000000000..2dc3a5dd1
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-av-audio.c
@@ -0,0 +1,361 @@
+/*
+ * cx18 ADEC audio functions
+ *
+ * Derived from cx25840-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "cx18-driver.h"
+
+static int set_audclk_freq(struct cx18 *cx, u32 freq)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ if (freq != 32000 && freq != 44100 && freq != 48000)
+ return -EINVAL;
+
+ /* common for all inputs and rates */
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
+ cx18_av_write(cx, 0x127, 0x50);
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ switch (freq) {
+ case 32000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1006040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x01bb39ee);
+
+ /* src3/4/6_ctl = 0x0801f77f */
+ cx18_av_write4(cx, 0x900, 0x0801f77f);
+ cx18_av_write4(cx, 0x904, 0x0801f77f);
+ cx18_av_write4(cx, 0x90c, 0x0801f77f);
+ break;
+
+ case 44100:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1009040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x00ec6bd6);
+
+ /* src3/4/6_ctl = 0x08016d59 */
+ cx18_av_write4(cx, 0x900, 0x08016d59);
+ cx18_av_write4(cx, 0x904, 0x08016d59);
+ cx18_av_write4(cx, 0x90c, 0x08016d59);
+ break;
+
+ case 48000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x100a040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x0098d6e5);
+
+ /* src3/4/6_ctl = 0x08014faa */
+ cx18_av_write4(cx, 0x900, 0x08014faa);
+ cx18_av_write4(cx, 0x904, 0x08014faa);
+ cx18_av_write4(cx, 0x90c, 0x08014faa);
+ break;
+ }
+ } else {
+ switch (freq) {
+ case 32000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1e08040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x012a0869);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x08010000);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08020000);
+ cx18_av_write4(cx, 0x904, 0x08020000);
+ cx18_av_write4(cx, 0x90c, 0x08020000);
+
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
+ cx18_av_write(cx, 0x127, 0x54);
+ break;
+
+ case 44100:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1809040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x00ec6bd6);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x080160cd);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08017385);
+ cx18_av_write4(cx, 0x904, 0x08017385);
+ cx18_av_write4(cx, 0x90c, 0x08017385);
+ break;
+
+ case 48000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x180a040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x0098d6e5);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x08018000);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08015555);
+ cx18_av_write4(cx, 0x904, 0x08015555);
+ cx18_av_write4(cx, 0x90c, 0x08015555);
+ break;
+ }
+ }
+
+ state->audclk_freq = freq;
+
+ return 0;
+}
+
+void cx18_av_audio_set_path(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ /* stop microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0);
+
+ /* assert soft reset */
+ cx18_av_and_or(cx, 0x810, ~0x1, 0x01);
+
+ /* Mute everything to prevent the PFFT! */
+ cx18_av_write(cx, 0x8d3, 0x1f);
+
+ if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
+ /* Set Path1 to Serial Audio Input */
+ cx18_av_write4(cx, 0x8d0, 0x01011012);
+
+ /* The microcontroller should not be started for the
+ * non-tuner inputs: autodetection is specific for
+ * TV audio. */
+ } else {
+ /* Set Path1 to Analog Demod Main Channel */
+ cx18_av_write4(cx, 0x8d0, 0x1f063870);
+ }
+
+ set_audclk_freq(cx, state->audclk_freq);
+
+ /* deassert soft reset */
+ cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ /* When the microcontroller detects the
+ * audio format, it will unmute the lines */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+}
+
+static int get_volume(struct cx18 *cx)
+{
+ /* Volume runs +18dB to -96dB in 1/2dB steps
+ * change to fit the msp3400 -114dB to +12dB range */
+
+ /* check PATH1_VOLUME */
+ int vol = 228 - cx18_av_read(cx, 0x8d4);
+ vol = (vol / 2) + 23;
+ return vol << 9;
+}
+
+static void set_volume(struct cx18 *cx, int volume)
+{
+ /* First convert the volume to msp3400 values (0-127) */
+ int vol = volume >> 9;
+ /* now scale it up to cx18_av values
+ * -114dB to -96dB maps to 0
+ * this should be 19, but in my testing that was 4dB too loud */
+ if (vol <= 23)
+ vol = 0;
+ else
+ vol -= 23;
+
+ /* PATH1_VOLUME */
+ cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
+}
+
+static int get_bass(struct cx18 *cx)
+{
+ /* bass is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_BASS_VOL */
+ int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
+ bass = (((48 - bass) * 0xffff) + 47) / 48;
+ return bass;
+}
+
+static void set_bass(struct cx18 *cx, int bass)
+{
+ /* PATH1_EQ_BASS_VOL */
+ cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
+}
+
+static int get_treble(struct cx18 *cx)
+{
+ /* treble is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_TREBLE_VOL */
+ int treble = cx18_av_read(cx, 0x8db) & 0x3f;
+ treble = (((48 - treble) * 0xffff) + 47) / 48;
+ return treble;
+}
+
+static void set_treble(struct cx18 *cx, int treble)
+{
+ /* PATH1_EQ_TREBLE_VOL */
+ cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
+}
+
+static int get_balance(struct cx18 *cx)
+{
+ /* balance is 7 bit, 0 to -96dB */
+
+ /* check PATH1_BAL_LEVEL */
+ int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
+ /* check PATH1_BAL_LEFT */
+ if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
+ balance = 0x80 - balance;
+ else
+ balance = 0x80 + balance;
+ return balance << 8;
+}
+
+static void set_balance(struct cx18 *cx, int balance)
+{
+ int bal = balance >> 8;
+ if (bal > 0x80) {
+ /* PATH1_BAL_LEFT */
+ cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80);
+ /* PATH1_BAL_LEVEL */
+ cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f);
+ } else {
+ /* PATH1_BAL_LEFT */
+ cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00);
+ /* PATH1_BAL_LEVEL */
+ cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal);
+ }
+}
+
+static int get_mute(struct cx18 *cx)
+{
+ /* check SRC1_MUTE_EN */
+ return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
+}
+
+static void set_mute(struct cx18 *cx, int mute)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ /* Must turn off microcontroller in order to mute sound.
+ * Not sure if this is the best method, but it does work.
+ * If the microcontroller is running, then it will undo any
+ * changes to the mute register. */
+ if (mute) {
+ /* disable microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
+ cx18_av_write(cx, 0x8d3, 0x1f);
+ } else {
+ /* enable microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+ } else {
+ /* SRC1_MUTE_EN */
+ cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+ }
+}
+
+int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_control *ctrl = arg;
+ int retval;
+
+ switch (cmd) {
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ cx18_av_and_or(cx, 0x803, ~0x10, 0);
+ cx18_av_write(cx, 0x8d3, 0x1f);
+ }
+ cx18_av_and_or(cx, 0x810, ~0x1, 1);
+ retval = set_audclk_freq(cx, *(u32 *)arg);
+ cx18_av_and_or(cx, 0x810, ~0x1, 0);
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL)
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ return retval;
+
+ case VIDIOC_G_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = get_volume(cx);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ ctrl->value = get_bass(cx);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ ctrl->value = get_treble(cx);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = get_balance(cx);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = get_mute(cx);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case VIDIOC_S_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ set_volume(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ set_bass(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ set_treble(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ set_balance(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ set_mute(cx, ctrl->value);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
new file mode 100644
index 000000000..8f2959ae7
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -0,0 +1,888 @@
+/*
+ * cx18 ADEC audio functions
+ *
+ * Derived from cx25840-core.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "cx18-driver.h"
+
+int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
+{
+ u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+ u32 mask = 0xff;
+ int shift = (addr & 3) * 8;
+
+ x = (x & ~(mask << shift)) | ((u32)value << shift);
+ writel(x, cx->reg_mem + 0xc40000 + (addr & ~3));
+ return 0;
+}
+
+int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
+{
+ writel(value, cx->reg_mem + 0xc40000 + addr);
+ return 0;
+}
+
+u8 cx18_av_read(struct cx18 *cx, u16 addr)
+{
+ u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+ int shift = (addr & 3) * 8;
+
+ return (x >> shift) & 0xff;
+}
+
+u32 cx18_av_read4(struct cx18 *cx, u16 addr)
+{
+ return readl(cx->reg_mem + 0xc40000 + addr);
+}
+
+int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
+ u8 or_value)
+{
+ return cx18_av_write(cx, addr,
+ (cx18_av_read(cx, addr) & and_mask) |
+ or_value);
+}
+
+int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
+ u32 or_value)
+{
+ return cx18_av_write4(cx, addr,
+ (cx18_av_read4(cx, addr) & and_mask) |
+ or_value);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ enum cx18_av_audio_input aud_input);
+static void log_audio_status(struct cx18 *cx);
+static void log_video_status(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+
+static void cx18_av_initialize(struct cx18 *cx)
+{
+ u32 v;
+
+ cx18_av_loadfw(cx);
+ /* Stop 8051 code execution */
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000);
+
+ /* initallize the PLL by toggling sleep bit */
+ v = cx18_av_read4(cx, CXADEC_HOST_REG1);
+ /* enable sleep mode */
+ cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1);
+ /* disable sleep mode */
+ cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe);
+
+ /* initialize DLLs */
+ v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF;
+ /* disable FLD */
+ cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v);
+ /* enable FLD */
+ cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100);
+
+ v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF;
+ /* disable FLD */
+ cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v);
+ /* enable FLD */
+ cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100);
+
+ /* set analog bias currents. Set Vreg to 1.20V. */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802);
+
+ v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1;
+ /* enable TUNE_FIL_RST */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v);
+ /* disable TUNE_FIL_RST */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE);
+
+ /* enable 656 output */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00);
+
+ /* video output drive strength */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2);
+
+ /* reset video */
+ cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
+ cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
+
+ /* set video to auto-detect */
+ /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */
+ /* set the comb notch = 1 */
+ cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800);
+
+ /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */
+ /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */
+ cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000);
+
+ /* Set VGA_TRACK_RANGE to 0x20 */
+ cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
+
+ /* Enable VBI capture */
+ cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
+ /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
+
+ /* Set the video input.
+ The setting in MODE_CTRL gets lost when we do the above setup */
+ /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
+ /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
+
+ v = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+ v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */
+ v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */
+ v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */
+ /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */
+ cx18_av_write4(cx, CXADEC_AFE_CTRL, v);
+
+/* if(dwEnable && dw3DCombAvailable) { */
+/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
+/* } else { */
+/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
+/* } */
+ cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void input_change(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ v4l2_std_id std = state->std;
+
+ /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
+ if (std & V4L2_STD_SECAM)
+ cx18_av_write(cx, 0x402, 0);
+ else {
+ cx18_av_write(cx, 0x402, 0x04);
+ cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+ }
+ cx18_av_and_or(cx, 0x401, ~0x60, 0);
+ cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
+
+ if (std & V4L2_STD_525_60) {
+ if (std == V4L2_STD_NTSC_M_JP) {
+ /* Japan uses EIAJ audio standard */
+ cx18_av_write(cx, 0x808, 0xf7);
+ cx18_av_write(cx, 0x80b, 0x02);
+ } else if (std == V4L2_STD_NTSC_M_KR) {
+ /* South Korea uses A2 audio standard */
+ cx18_av_write(cx, 0x808, 0xf8);
+ cx18_av_write(cx, 0x80b, 0x03);
+ } else {
+ /* Others use the BTSC audio standard */
+ cx18_av_write(cx, 0x808, 0xf6);
+ cx18_av_write(cx, 0x80b, 0x01);
+ }
+ } else if (std & V4L2_STD_PAL) {
+ /* Follow tuner change procedure for PAL */
+ cx18_av_write(cx, 0x808, 0xff);
+ cx18_av_write(cx, 0x80b, 0x03);
+ } else if (std & V4L2_STD_SECAM) {
+ /* Select autodetect for SECAM */
+ cx18_av_write(cx, 0x808, 0xff);
+ cx18_av_write(cx, 0x80b, 0x03);
+ }
+
+ if (cx18_av_read(cx, 0x803) & 0x10) {
+ /* restart audio decoder microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+}
+
+static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ enum cx18_av_audio_input aud_input)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
+ vid_input <= CX18_AV_COMPOSITE8);
+ u8 reg;
+
+ CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
+ vid_input, aud_input);
+
+ if (is_composite) {
+ reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+ } else {
+ int luma = vid_input & 0xf0;
+ int chroma = vid_input & 0xf00;
+
+ if ((vid_input & ~0xff0) ||
+ luma < CX18_AV_SVIDEO_LUMA1 ||
+ luma > CX18_AV_SVIDEO_LUMA8 ||
+ chroma < CX18_AV_SVIDEO_CHROMA4 ||
+ chroma > CX18_AV_SVIDEO_CHROMA8) {
+ CX18_ERR("0x%04x is not a valid video input!\n",
+ vid_input);
+ return -EINVAL;
+ }
+ reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+ if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
+ reg &= 0x3f;
+ reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+ } else {
+ reg &= 0xcf;
+ reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+ }
+ }
+
+ switch (aud_input) {
+ case CX18_AV_AUDIO_SERIAL:
+ /* do nothing, use serial audio input */
+ break;
+ case CX18_AV_AUDIO4: reg &= ~0x30; break;
+ case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+ case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+ case CX18_AV_AUDIO7: reg &= ~0xc0; break;
+ case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+
+ default:
+ CX18_ERR("0x%04x is not a valid audio input!\n", aud_input);
+ return -EINVAL;
+ }
+
+ cx18_av_write(cx, 0x103, reg);
+ /* Set INPUT_MODE to Composite (0) or S-Video (1) */
+ cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+ /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+ cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+ /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
+ if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+ cx18_av_and_or(cx, 0x102, ~0x4, 4);
+ else
+ cx18_av_and_or(cx, 0x102, ~0x4, 0);
+ /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
+
+ state->vid_input = vid_input;
+ state->aud_input = aud_input;
+ cx18_av_audio_set_path(cx);
+ input_change(cx);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lstd(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 fmt = 0; /* zero is autodetect */
+ u8 pal_m = 0;
+
+ /* First tests should be against specific std */
+ if (state->std == V4L2_STD_NTSC_M_JP) {
+ fmt = 0x2;
+ } else if (state->std == V4L2_STD_NTSC_443) {
+ fmt = 0x3;
+ } else if (state->std == V4L2_STD_PAL_M) {
+ pal_m = 1;
+ fmt = 0x5;
+ } else if (state->std == V4L2_STD_PAL_N) {
+ fmt = 0x6;
+ } else if (state->std == V4L2_STD_PAL_Nc) {
+ fmt = 0x7;
+ } else if (state->std == V4L2_STD_PAL_60) {
+ fmt = 0x8;
+ } else {
+ /* Then, test against generic ones */
+ if (state->std & V4L2_STD_NTSC)
+ fmt = 0x1;
+ else if (state->std & V4L2_STD_PAL)
+ fmt = 0x4;
+ else if (state->std & V4L2_STD_SECAM)
+ fmt = 0xc;
+ }
+
+ CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt);
+
+ /* Follow step 9 of section 3.16 in the cx18_av datasheet.
+ Without this PAL may display a vertical ghosting effect.
+ This happens for example with the Yuan MPC622. */
+ if (fmt >= 4 && fmt < 8) {
+ /* Set format to NTSC-M */
+ cx18_av_and_or(cx, 0x400, ~0xf, 1);
+ /* Turn off LCOMB */
+ cx18_av_and_or(cx, 0x47b, ~6, 0);
+ }
+ cx18_av_and_or(cx, 0x400, ~0xf, fmt);
+ cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+ cx18_av_vbi_setup(cx);
+ input_change(cx);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ CX18_ERR("invalid brightness setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x414, ctrl->value - 128);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ CX18_ERR("invalid contrast setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x415, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ CX18_ERR("invalid saturation setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x420, ctrl->value << 1);
+ cx18_av_write(cx, 0x421, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ CX18_ERR("invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x422, ctrl->value);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = cx18_av_read(cx, 0x415) >> 1;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = cx18_av_read(cx, 0x420) >> 1;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = (s8)cx18_av_read(cx, 0x422);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+{
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_pix_format *pix;
+ int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+ int is_50Hz = !(state->std & V4L2_STD_525_60);
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pix = &(fmt->fmt.pix);
+
+ Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
+
+ Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
+
+ Vlines = pix->height + (is_50Hz ? 4 : 7);
+
+ if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ CX18_ERR("%dx%d is not a valid size!\n",
+ pix->width, pix->height);
+ return -ERANGE;
+ }
+
+ HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
+
+ if (pix->width >= 385)
+ filter = 0;
+ else if (pix->width > 192)
+ filter = 1;
+ else if (pix->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ CX18_DEBUG_INFO("decoder set size %dx%d -> scale %ux%u\n",
+ pix->width, pix->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx18_av_write(cx, 0x418, HSC & 0xff);
+ cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
+ cx18_av_write(cx, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx18_av_write(cx, 0x41c, VSC & 0xff);
+ cx18_av_write(cx, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx18_av_write(cx, 0x41e, 0x8 | filter);
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_tuner *vt = arg;
+ struct v4l2_routing *route = arg;
+
+ /* ignore these commands */
+ switch (cmd) {
+ case TUNER_SET_TYPE_ADDR:
+ return 0;
+ }
+
+ if (!state->is_initialized) {
+ CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd);
+ /* initialize on first use */
+ state->is_initialized = 1;
+ cx18_av_initialize(cx);
+ }
+
+ switch (cmd) {
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ return cx18_av_vbi(cx, cmd, arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return cx18_av_audio(cx, cmd, arg);
+
+ case VIDIOC_STREAMON:
+ CX18_DEBUG_INFO("enable output\n");
+ cx18_av_write(cx, 0x115, 0x8c);
+ cx18_av_write(cx, 0x116, 0x07);
+ break;
+
+ case VIDIOC_STREAMOFF:
+ CX18_DEBUG_INFO("disable output\n");
+ cx18_av_write(cx, 0x115, 0x00);
+ cx18_av_write(cx, 0x116, 0x00);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ log_video_status(cx);
+ log_audio_status(cx);
+ break;
+
+ case VIDIOC_G_CTRL:
+ return get_v4lctrl(cx, (struct v4l2_control *)arg);
+
+ case VIDIOC_S_CTRL:
+ return set_v4lctrl(cx, (struct v4l2_control *)arg);
+
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
+
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = state->std;
+ break;
+
+ case VIDIOC_S_STD:
+ if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
+ return 0;
+ state->radio = 0;
+ state->std = *(v4l2_std_id *)arg;
+ return set_v4lstd(cx);
+
+ case AUDC_SET_RADIO:
+ state->radio = 1;
+ break;
+
+ case VIDIOC_INT_G_VIDEO_ROUTING:
+ route->input = state->vid_input;
+ route->output = 0;
+ break;
+
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ return set_input(cx, route->input, state->aud_input);
+
+ case VIDIOC_INT_G_AUDIO_ROUTING:
+ route->input = state->aud_input;
+ route->output = 0;
+ break;
+
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ return set_input(cx, state->vid_input, route->input);
+
+ case VIDIOC_S_FREQUENCY:
+ input_change(cx);
+ break;
+
+ case VIDIOC_G_TUNER:
+ {
+ u8 vpres = cx18_av_read(cx, 0x40e) & 0x20;
+ u8 mode;
+ int val = 0;
+
+ if (state->radio)
+ break;
+
+ vt->signal = vpres ? 0xffff : 0x0;
+
+ vt->capability |=
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+ mode = cx18_av_read(cx, 0x804);
+
+ /* get rxsubchans and audmode */
+ if ((mode & 0xf) == 1)
+ val |= V4L2_TUNER_SUB_STEREO;
+ else
+ val |= V4L2_TUNER_SUB_MONO;
+
+ if (mode == 2 || mode == 4)
+ val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+ if (mode & 0x10)
+ val |= V4L2_TUNER_SUB_SAP;
+
+ vt->rxsubchans = val;
+ vt->audmode = state->audmode;
+ break;
+ }
+
+ case VIDIOC_S_TUNER:
+ if (state->radio)
+ break;
+
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ /* mono -> mono
+ stereo -> mono
+ bilingual -> lang1 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x00);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ case V4L2_TUNER_MODE_LANG1:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang1 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x04);
+ break;
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang1/lang2 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x07);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang2 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x01);
+ break;
+ default:
+ return -EINVAL;
+ }
+ state->audmode = vt->audmode;
+ break;
+
+ case VIDIOC_G_FMT:
+ return get_v4lfmt(cx, (struct v4l2_format *)arg);
+
+ case VIDIOC_S_FMT:
+ return set_v4lfmt(cx, (struct v4l2_format *)arg);
+
+ case VIDIOC_INT_RESET:
+ cx18_av_initialize(cx);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+
+static void log_video_status(struct cx18 *cx)
+{
+ static const char *const fmt_strs[] = {
+ "0x0",
+ "NTSC-M", "NTSC-J", "NTSC-4.43",
+ "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+ "0x9", "0xA", "0xB",
+ "SECAM",
+ "0xD", "0xE", "0xF"
+ };
+
+ struct cx18_av_state *state = &cx->av_state;
+ u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf;
+ u8 gen_stat1 = cx18_av_read(cx, 0x40d);
+ u8 gen_stat2 = cx18_av_read(cx, 0x40e);
+ int vid_input = state->vid_input;
+
+ CX18_INFO("Video signal: %spresent\n",
+ (gen_stat2 & 0x20) ? "" : "not ");
+ CX18_INFO("Detected format: %s\n",
+ fmt_strs[gen_stat1 & 0xf]);
+
+ CX18_INFO("Specified standard: %s\n",
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+ if (vid_input >= CX18_AV_COMPOSITE1 &&
+ vid_input <= CX18_AV_COMPOSITE8) {
+ CX18_INFO("Specified video input: Composite %d\n",
+ vid_input - CX18_AV_COMPOSITE1 + 1);
+ } else {
+ CX18_INFO("Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+ (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+ }
+
+ CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 download_ctl = cx18_av_read(cx, 0x803);
+ u8 mod_det_stat0 = cx18_av_read(cx, 0x804);
+ u8 mod_det_stat1 = cx18_av_read(cx, 0x805);
+ u8 audio_config = cx18_av_read(cx, 0x808);
+ u8 pref_mode = cx18_av_read(cx, 0x809);
+ u8 afc0 = cx18_av_read(cx, 0x80b);
+ u8 mute_ctl = cx18_av_read(cx, 0x8d3);
+ int aud_input = state->aud_input;
+ char *p;
+
+ switch (mod_det_stat0) {
+ case 0x00: p = "mono"; break;
+ case 0x01: p = "stereo"; break;
+ case 0x02: p = "dual"; break;
+ case 0x04: p = "tri"; break;
+ case 0x10: p = "mono with SAP"; break;
+ case 0x11: p = "stereo with SAP"; break;
+ case 0x12: p = "dual with SAP"; break;
+ case 0x14: p = "tri with SAP"; break;
+ case 0xfe: p = "forced mode"; break;
+ default: p = "not defined"; break;
+ }
+ CX18_INFO("Detected audio mode: %s\n", p);
+
+ switch (mod_det_stat1) {
+ case 0x00: p = "not defined"; break;
+ case 0x01: p = "EIAJ"; break;
+ case 0x02: p = "A2-M"; break;
+ case 0x03: p = "A2-BG"; break;
+ case 0x04: p = "A2-DK1"; break;
+ case 0x05: p = "A2-DK2"; break;
+ case 0x06: p = "A2-DK3"; break;
+ case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x08: p = "AM-L"; break;
+ case 0x09: p = "NICAM-BG"; break;
+ case 0x0a: p = "NICAM-DK"; break;
+ case 0x0b: p = "NICAM-I"; break;
+ case 0x0c: p = "NICAM-L"; break;
+ case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+ case 0x0e: p = "IF FM Radio"; break;
+ case 0x0f: p = "BTSC"; break;
+ case 0x10: p = "detected chrominance"; break;
+ case 0xfd: p = "unknown audio standard"; break;
+ case 0xfe: p = "forced audio standard"; break;
+ case 0xff: p = "no detected audio standard"; break;
+ default: p = "not defined"; break;
+ }
+ CX18_INFO("Detected audio standard: %s\n", p);
+ CX18_INFO("Audio muted: %s\n",
+ (mute_ctl & 0x2) ? "yes" : "no");
+ CX18_INFO("Audio microcontroller: %s\n",
+ (download_ctl & 0x10) ? "running" : "stopped");
+
+ switch (audio_config >> 4) {
+ case 0x00: p = "undefined"; break;
+ case 0x01: p = "BTSC"; break;
+ case 0x02: p = "EIAJ"; break;
+ case 0x03: p = "A2-M"; break;
+ case 0x04: p = "A2-BG"; break;
+ case 0x05: p = "A2-DK1"; break;
+ case 0x06: p = "A2-DK2"; break;
+ case 0x07: p = "A2-DK3"; break;
+ case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x09: p = "AM-L"; break;
+ case 0x0a: p = "NICAM-BG"; break;
+ case 0x0b: p = "NICAM-DK"; break;
+ case 0x0c: p = "NICAM-I"; break;
+ case 0x0d: p = "NICAM-L"; break;
+ case 0x0e: p = "FM radio"; break;
+ case 0x0f: p = "automatic detection"; break;
+ default: p = "undefined"; break;
+ }
+ CX18_INFO("Configured audio standard: %s\n", p);
+
+ if ((audio_config >> 4) < 0xF) {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+ case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+ case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+ case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+ case 0x04: p = "STEREO"; break;
+ case 0x05: p = "DUAL1 (AC)"; break;
+ case 0x06: p = "DUAL2 (BC)"; break;
+ case 0x07: p = "DUAL3 (AB)"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Configured audio mode: %s\n", p);
+ } else {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "BG"; break;
+ case 0x01: p = "DK1"; break;
+ case 0x02: p = "DK2"; break;
+ case 0x03: p = "DK3"; break;
+ case 0x04: p = "I"; break;
+ case 0x05: p = "L"; break;
+ case 0x06: p = "BTSC"; break;
+ case 0x07: p = "EIAJ"; break;
+ case 0x08: p = "A2-M"; break;
+ case 0x09: p = "FM Radio (4.5 MHz)"; break;
+ case 0x0a: p = "FM Radio (5.5 MHz)"; break;
+ case 0x0b: p = "S-Video"; break;
+ case 0x0f: p = "automatic standard and mode detection"; break;
+ default: p = "undefined"; break;
+ }
+ CX18_INFO("Configured audio system: %s\n", p);
+ }
+
+ if (aud_input)
+ CX18_INFO("Specified audio input: Tuner (In%d)\n",
+ aud_input);
+ else
+ CX18_INFO("Specified audio input: External\n");
+
+ switch (pref_mode & 0xf) {
+ case 0: p = "mono/language A"; break;
+ case 1: p = "language B"; break;
+ case 2: p = "language C"; break;
+ case 3: p = "analog fallback"; break;
+ case 4: p = "stereo"; break;
+ case 5: p = "language AC"; break;
+ case 6: p = "language BC"; break;
+ case 7: p = "language AB"; break;
+ default: p = "undefined"; break;
+ }
+ CX18_INFO("Preferred audio mode: %s\n", p);
+
+ if ((audio_config & 0xf) == 0xf) {
+ switch ((afc0 >> 3) & 0x1) {
+ case 0: p = "system DK"; break;
+ case 1: p = "system L"; break;
+ }
+ CX18_INFO("Selected 65 MHz format: %s\n", p);
+
+ switch (afc0 & 0x7) {
+ case 0: p = "Chroma"; break;
+ case 1: p = "BTSC"; break;
+ case 2: p = "EIAJ"; break;
+ case 3: p = "A2-M"; break;
+ case 4: p = "autodetect"; break;
+ default: p = "undefined"; break;
+ }
+ CX18_INFO("Selected 45 MHz format: %s\n", p);
+ }
+}
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.h b/linux/drivers/media/video/cx18/cx18-av-core.h
new file mode 100644
index 000000000..39f3c9397
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-av-core.h
@@ -0,0 +1,322 @@
+/*
+ * cx18 ADEC header
+ *
+ * Derived from cx25840-core.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef _CX18_AV_CORE_H_
+#define _CX18_AV_CORE_H_
+
+struct cx18;
+
+enum cx18_av_video_input {
+ /* Composite video inputs In1-In8 */
+ CX18_AV_COMPOSITE1 = 1,
+ CX18_AV_COMPOSITE2,
+ CX18_AV_COMPOSITE3,
+ CX18_AV_COMPOSITE4,
+ CX18_AV_COMPOSITE5,
+ CX18_AV_COMPOSITE6,
+ CX18_AV_COMPOSITE7,
+ CX18_AV_COMPOSITE8,
+
+ /* S-Video inputs consist of one luma input (In1-In8) ORed with one
+ chroma input (In5-In8) */
+ CX18_AV_SVIDEO_LUMA1 = 0x10,
+ CX18_AV_SVIDEO_LUMA2 = 0x20,
+ CX18_AV_SVIDEO_LUMA3 = 0x30,
+ CX18_AV_SVIDEO_LUMA4 = 0x40,
+ CX18_AV_SVIDEO_LUMA5 = 0x50,
+ CX18_AV_SVIDEO_LUMA6 = 0x60,
+ CX18_AV_SVIDEO_LUMA7 = 0x70,
+ CX18_AV_SVIDEO_LUMA8 = 0x80,
+ CX18_AV_SVIDEO_CHROMA4 = 0x400,
+ CX18_AV_SVIDEO_CHROMA5 = 0x500,
+ CX18_AV_SVIDEO_CHROMA6 = 0x600,
+ CX18_AV_SVIDEO_CHROMA7 = 0x700,
+ CX18_AV_SVIDEO_CHROMA8 = 0x800,
+
+ /* S-Video aliases for common luma/chroma combinations */
+ CX18_AV_SVIDEO1 = 0x510,
+ CX18_AV_SVIDEO2 = 0x620,
+ CX18_AV_SVIDEO3 = 0x730,
+ CX18_AV_SVIDEO4 = 0x840,
+};
+
+enum cx18_av_audio_input {
+ /* Audio inputs: serial or In4-In8 */
+ CX18_AV_AUDIO_SERIAL,
+ CX18_AV_AUDIO4 = 4,
+ CX18_AV_AUDIO5,
+ CX18_AV_AUDIO6,
+ CX18_AV_AUDIO7,
+ CX18_AV_AUDIO8,
+};
+
+struct cx18_av_state {
+ int radio;
+ v4l2_std_id std;
+ enum cx18_av_video_input vid_input;
+ enum cx18_av_audio_input aud_input;
+ u32 audclk_freq;
+ int audmode;
+ int vbi_line_offset;
+ u32 id;
+ u32 rev;
+ int is_initialized;
+};
+
+
+/* Registers */
+#define CXADEC_CHIP_TYPE_TIGER 0x837
+#define CXADEC_CHIP_TYPE_MAKO 0x843
+
+#define CXADEC_HOST_REG1 0x000
+#define CXADEC_HOST_REG2 0x001
+
+#define CXADEC_CHIP_CTRL 0x100
+#define CXADEC_AFE_CTRL 0x104
+#define CXADEC_PLL_CTRL1 0x108
+#define CXADEC_VID_PLL_FRAC 0x10C
+#define CXADEC_AUX_PLL_FRAC 0x110
+#define CXADEC_PIN_CTRL1 0x114
+#define CXADEC_PIN_CTRL2 0x118
+#define CXADEC_PIN_CFG1 0x11C
+#define CXADEC_PIN_CFG2 0x120
+
+#define CXADEC_PIN_CFG3 0x124
+#define CXADEC_I2S_MCLK 0x127
+
+#define CXADEC_AUD_LOCK1 0x128
+#define CXADEC_AUD_LOCK2 0x12C
+#define CXADEC_POWER_CTRL 0x130
+#define CXADEC_AFE_DIAG_CTRL1 0x134
+#define CXADEC_AFE_DIAG_CTRL2 0x138
+#define CXADEC_AFE_DIAG_CTRL3 0x13C
+#define CXADEC_PLL_DIAG_CTRL 0x140
+#define CXADEC_TEST_CTRL1 0x144
+#define CXADEC_TEST_CTRL2 0x148
+#define CXADEC_BIST_STAT 0x14C
+#define CXADEC_DLL1_DIAG_CTRL 0x158
+#define CXADEC_DLL2_DIAG_CTRL 0x15C
+
+/* IR registers */
+#define CXADEC_IR_CTRL_REG 0x200
+#define CXADEC_IR_TXCLK_REG 0x204
+#define CXADEC_IR_RXCLK_REG 0x208
+#define CXADEC_IR_CDUTY_REG 0x20C
+#define CXADEC_IR_STAT_REG 0x210
+#define CXADEC_IR_IRQEN_REG 0x214
+#define CXADEC_IR_FILTER_REG 0x218
+#define CXADEC_IR_FIFO_REG 0x21C
+
+/* Video Registers */
+#define CXADEC_MODE_CTRL 0x400
+#define CXADEC_OUT_CTRL1 0x404
+#define CXADEC_OUT_CTRL2 0x408
+#define CXADEC_GEN_STAT 0x40C
+#define CXADEC_INT_STAT_MASK 0x410
+#define CXADEC_LUMA_CTRL 0x414
+
+#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414
+#define CXADEC_CONTRAST_CTRL_BYTE 0x415
+#define CXADEC_LUMA_CTRL_BYTE_3 0x416
+
+#define CXADEC_HSCALE_CTRL 0x418
+#define CXADEC_VSCALE_CTRL 0x41C
+
+#define CXADEC_CHROMA_CTRL 0x420
+
+#define CXADEC_USAT_CTRL_BYTE 0x420
+#define CXADEC_VSAT_CTRL_BYTE 0x421
+#define CXADEC_HUE_CTRL_BYTE 0x422
+
+#define CXADEC_VBI_LINE_CTRL1 0x424
+#define CXADEC_VBI_LINE_CTRL2 0x428
+#define CXADEC_VBI_LINE_CTRL3 0x42C
+#define CXADEC_VBI_LINE_CTRL4 0x430
+#define CXADEC_VBI_LINE_CTRL5 0x434
+#define CXADEC_VBI_FC_CFG 0x438
+#define CXADEC_VBI_MISC_CFG1 0x43C
+#define CXADEC_VBI_MISC_CFG2 0x440
+#define CXADEC_VBI_PAY1 0x444
+#define CXADEC_VBI_PAY2 0x448
+#define CXADEC_VBI_CUST1_CFG1 0x44C
+#define CXADEC_VBI_CUST1_CFG2 0x450
+#define CXADEC_VBI_CUST1_CFG3 0x454
+#define CXADEC_VBI_CUST2_CFG1 0x458
+#define CXADEC_VBI_CUST2_CFG2 0x45C
+#define CXADEC_VBI_CUST2_CFG3 0x460
+#define CXADEC_VBI_CUST3_CFG1 0x464
+#define CXADEC_VBI_CUST3_CFG2 0x468
+#define CXADEC_VBI_CUST3_CFG3 0x46C
+#define CXADEC_HORIZ_TIM_CTRL 0x470
+#define CXADEC_VERT_TIM_CTRL 0x474
+#define CXADEC_SRC_COMB_CFG 0x478
+#define CXADEC_CHROMA_VBIOFF_CFG 0x47C
+#define CXADEC_FIELD_COUNT 0x480
+#define CXADEC_MISC_TIM_CTRL 0x484
+#define CXADEC_DFE_CTRL1 0x488
+#define CXADEC_DFE_CTRL2 0x48C
+#define CXADEC_DFE_CTRL3 0x490
+#define CXADEC_PLL_CTRL2 0x494
+#define CXADEC_HTL_CTRL 0x498
+#define CXADEC_COMB_CTRL 0x49C
+#define CXADEC_CRUSH_CTRL 0x4A0
+#define CXADEC_SOFT_RST_CTRL 0x4A4
+#define CXADEC_MV_DT_CTRL2 0x4A8
+#define CXADEC_MV_DT_CTRL3 0x4AC
+#define CXADEC_MISC_DIAG_CTRL 0x4B8
+
+#define CXADEC_DL_CTL 0x800
+#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */
+#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */
+#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */
+#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */
+
+#define CXADEC_STD_DET_STATUS 0x804
+
+#define CXADEC_STD_DET_CTL 0x808
+#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */
+#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */
+
+#define CXADEC_DW8051_INT 0x80C
+#define CXADEC_GENERAL_CTL 0x810
+#define CXADEC_AAGC_CTL 0x814
+#define CXADEC_IF_SRC_CTL 0x818
+#define CXADEC_ANLOG_DEMOD_CTL 0x81C
+#define CXADEC_ROT_FREQ_CTL 0x820
+#define CXADEC_FM1_CTL 0x824
+#define CXADEC_PDF_CTL 0x828
+#define CXADEC_DFT1_CTL1 0x82C
+#define CXADEC_DFT1_CTL2 0x830
+#define CXADEC_DFT_STATUS 0x834
+#define CXADEC_DFT2_CTL1 0x838
+#define CXADEC_DFT2_CTL2 0x83C
+#define CXADEC_DFT2_STATUS 0x840
+#define CXADEC_DFT3_CTL1 0x844
+#define CXADEC_DFT3_CTL2 0x848
+#define CXADEC_DFT3_STATUS 0x84C
+#define CXADEC_DFT4_CTL1 0x850
+#define CXADEC_DFT4_CTL2 0x854
+#define CXADEC_DFT4_STATUS 0x858
+#define CXADEC_AM_MTS_DET 0x85C
+#define CXADEC_ANALOG_MUX_CTL 0x860
+#define CXADEC_DIG_PLL_CTL1 0x864
+#define CXADEC_DIG_PLL_CTL2 0x868
+#define CXADEC_DIG_PLL_CTL3 0x86C
+#define CXADEC_DIG_PLL_CTL4 0x870
+#define CXADEC_DIG_PLL_CTL5 0x874
+#define CXADEC_DEEMPH_GAIN_CTL 0x878
+#define CXADEC_DEEMPH_COEF1 0x87C
+#define CXADEC_DEEMPH_COEF2 0x880
+#define CXADEC_DBX1_CTL1 0x884
+#define CXADEC_DBX1_CTL2 0x888
+#define CXADEC_DBX1_STATUS 0x88C
+#define CXADEC_DBX2_CTL1 0x890
+#define CXADEC_DBX2_CTL2 0x894
+#define CXADEC_DBX2_STATUS 0x898
+#define CXADEC_AM_FM_DIFF 0x89C
+
+/* NICAM registers go here */
+#define CXADEC_NICAM_STATUS 0x8C8
+#define CXADEC_DEMATRIX_CTL 0x8CC
+
+#define CXADEC_PATH1_CTL1 0x8D0
+#define CXADEC_PATH1_VOL_CTL 0x8D4
+#define CXADEC_PATH1_EQ_CTL 0x8D8
+#define CXADEC_PATH1_SC_CTL 0x8DC
+
+#define CXADEC_PATH2_CTL1 0x8E0
+#define CXADEC_PATH2_VOL_CTL 0x8E4
+#define CXADEC_PATH2_EQ_CTL 0x8E8
+#define CXADEC_PATH2_SC_CTL 0x8EC
+
+#define CXADEC_SRC_CTL 0x8F0
+#define CXADEC_SRC_LF_COEF 0x8F4
+#define CXADEC_SRC1_CTL 0x8F8
+#define CXADEC_SRC2_CTL 0x8FC
+#define CXADEC_SRC3_CTL 0x900
+#define CXADEC_SRC4_CTL 0x904
+#define CXADEC_SRC5_CTL 0x908
+#define CXADEC_SRC6_CTL 0x90C
+
+#define CXADEC_BASEBAND_OUT_SEL 0x910
+#define CXADEC_I2S_IN_CTL 0x914
+#define CXADEC_I2S_OUT_CTL 0x918
+#define CXADEC_AC97_CTL 0x91C
+#define CXADEC_QAM_PDF 0x920
+#define CXADEC_QAM_CONST_DEC 0x924
+#define CXADEC_QAM_ROTATOR_FREQ 0x948
+
+/* Bit defintions / settings used in Mako Audio */
+#define CXADEC_PREF_MODE_MONO_LANGA 0
+#define CXADEC_PREF_MODE_MONO_LANGB 1
+#define CXADEC_PREF_MODE_MONO_LANGC 2
+#define CXADEC_PREF_MODE_FALLBACK 3
+#define CXADEC_PREF_MODE_STEREO 4
+#define CXADEC_PREF_MODE_DUAL_LANG_AC 5
+#define CXADEC_PREF_MODE_DUAL_LANG_BC 6
+#define CXADEC_PREF_MODE_DUAL_LANG_AB 7
+
+
+#define CXADEC_DETECT_STEREO 1
+#define CXADEC_DETECT_DUAL 2
+#define CXADEC_DETECT_TRI 4
+#define CXADEC_DETECT_SAP 0x10
+#define CXADEC_DETECT_NO_SIGNAL 0xFF
+
+#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */
+#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */
+#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2
+#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3
+#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */
+#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */
+#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6
+#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7
+#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */
+#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
+#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-core.c */
+int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
+int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
+u8 cx18_av_read(struct cx18 *cx, u16 addr);
+u32 cx18_av_read4(struct cx18 *cx, u16 addr);
+int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
+int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
+int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-firmware.c */
+int cx18_av_loadfw(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-audio.c */
+int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg);
+void cx18_av_audio_set_path(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-vbi.c */
+void cx18_av_vbi_setup(struct cx18 *cx);
+int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
+
+#endif
diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c
new file mode 100644
index 000000000..526e14215
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c
@@ -0,0 +1,120 @@
+/*
+ * cx18 ADEC firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "cx18-driver.h"
+#include <linux/firmware.h>
+
+#define FWFILE "v4l-cx23418-dig.fw"
+
+int cx18_av_loadfw(struct cx18 *cx)
+{
+ const struct firmware *fw = NULL;
+ u32 size;
+ u32 v;
+ u8 *ptr;
+ int i;
+
+ if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
+ CX18_ERR("unable to open firmware %s\n", FWFILE);
+ return -EINVAL;
+ }
+
+ cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
+ cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
+
+ /* Reset the Mako core (Register is undocumented.) */
+ cx18_av_write4(cx, 0x8100, 0x00010000);
+
+ /* Put the 8051 in reset and enable firmware upload */
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+
+ ptr = fw->data;
+ size = fw->size;
+
+ for (i = 0; i < size; i++) {
+ u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
+ u32 value = 0;
+ int retries;
+
+ for (retries = 0; retries < 5; retries++) {
+ cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+ value = cx18_av_read4(cx, CXADEC_DL_CTL);
+ if ((value & 0x3F00) == (dl_control & 0x3F00))
+ break;
+ }
+ if (retries >= 5) {
+ CX18_ERR("unable to load firmware %s\n", FWFILE);
+ release_firmware(fw);
+ return -EIO;
+ }
+ }
+
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
+
+ /* Output to the 416 */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
+
+ /* Audio input control 1 set to Sony mode */
+ /* Audio output input 2 is 0 for slave operation input */
+ /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+ /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+ after WS transition for first bit of audio word. */
+ cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0);
+
+ /* Audio output control 1 is set to Sony mode */
+ /* Audio output control 2 is set to 1 for master mode */
+ /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+ /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+ after WS transition for first bit of audio word. */
+ /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT
+ are generated) */
+ cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
+
+ /* set alt I2s master clock to /16 and enable alt divider i2s
+ passthrough */
+ cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
+
+ cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6);
+ /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
+
+ /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
+ /* Register 0x09CC is defined by the Merlin firmware, and doesn't
+ have a name in the spec. */
+ cx18_av_write4(cx, 0x09CC, 1);
+
+#define CX18_AUDIO_ENABLE 0xc72014
+ v = read_reg(CX18_AUDIO_ENABLE);
+ /* If bit 11 is 1 */
+ if (v & 0x800)
+ write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */
+
+ /* Enable WW auto audio standard detection */
+ v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
+ v |= 0xFF; /* Auto by default */
+ v |= 0x400; /* Stereo by default */
+ v |= 0x14000000;
+ cx18_av_write4(cx, CXADEC_STD_DET_CTL, v);
+
+ release_firmware(fw);
+
+ CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size);
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c
new file mode 100644
index 000000000..d09f1daf4
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c
@@ -0,0 +1,413 @@
+/*
+ * cx18 ADEC VBI functions
+ *
+ * Derived from cx25840-vbi.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include "cx18-driver.h"
+
+static int odd_parity(u8 c)
+{
+ c ^= (c >> 4);
+ c ^= (c >> 2);
+ c ^= (c >> 1);
+
+ return c & 1;
+}
+
+static int decode_vps(u8 *dst, u8 *p)
+{
+ static const u8 biphase_tbl[] = {
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+ 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+ 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+ 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+ 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+ 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+ 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ };
+
+ u8 c, err = 0;
+ int i;
+
+ for (i = 0; i < 2 * 13; i += 2) {
+ err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+ c = (biphase_tbl[p[i + 1]] & 0xf) |
+ ((biphase_tbl[p[i]] & 0xf) << 4);
+ dst[i / 2] = c;
+ }
+
+ return err & 0xf0;
+}
+
+void cx18_av_vbi_setup(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ v4l2_std_id std = state->std;
+ int hblank, hactive, burst, vblank, vactive, sc;
+ int vblank656, src_decimation;
+ int luma_lpf, uv_lpf, comb;
+ u32 pll_int, pll_frac, pll_post;
+
+ /* datasheet startup, step 8d */
+ if (std & ~V4L2_STD_NTSC)
+ cx18_av_write(cx, 0x49f, 0x11);
+ else
+ cx18_av_write(cx, 0x49f, 0x14);
+
+ if (std & V4L2_STD_625_50) {
+ hblank = 0x084;
+ hactive = 0x2d0;
+ burst = 0x5d;
+ vblank = 0x024;
+ vactive = 0x244;
+ vblank656 = 0x28;
+ src_decimation = 0x21f;
+
+ luma_lpf = 2;
+ if (std & V4L2_STD_SECAM) {
+ uv_lpf = 0;
+ comb = 0;
+ sc = 0x0a425f;
+ } else if (std == V4L2_STD_PAL_Nc) {
+ uv_lpf = 1;
+ comb = 0x20;
+ sc = 556453;
+ } else {
+ uv_lpf = 1;
+ comb = 0x20;
+ sc = 0x0a8263;
+ }
+ } else {
+ hactive = 720;
+ hblank = 122;
+ vactive = 487;
+ luma_lpf = 1;
+ uv_lpf = 1;
+
+ src_decimation = 0x21f;
+ if (std == V4L2_STD_PAL_60) {
+ vblank = 26;
+ vblank656 = 26;
+ burst = 0x5b;
+ luma_lpf = 2;
+ comb = 0x20;
+ sc = 0x0a8263;
+ } else if (std == V4L2_STD_PAL_M) {
+ vblank = 20;
+ vblank656 = 24;
+ burst = 0x61;
+ comb = 0x20;
+
+ sc = 555452;
+ } else {
+ vblank = 26;
+ vblank656 = 26;
+ burst = 0x5b;
+ comb = 0x66;
+ sc = 556063;
+ }
+ }
+
+ /* DEBUG: Displays configured PLL frequency */
+ pll_int = cx18_av_read(cx, 0x108);
+ pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
+ pll_post = cx18_av_read(cx, 0x109);
+ CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
+ pll_int, pll_frac, pll_post);
+
+ if (pll_post) {
+ int fin, fsc;
+ int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
+
+ pll >>= 25;
+ pll /= pll_post;
+ CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
+ pll / 1000000, pll % 1000000);
+ CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
+ pll / 8000000, (pll / 8) % 1000000);
+
+ fin = ((u64)src_decimation * pll) >> 12;
+ CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
+ fin / 1000000, fin % 1000000);
+
+ fsc = (((u64)sc) * pll) >> 24L;
+ CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
+ fsc / 1000000, fsc % 1000000);
+
+ CX18_DEBUG_INFO("hblank %i, hactive %i, "
+ "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+ "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+ " sc 0x%06x\n",
+ hblank, hactive, vblank, vactive, vblank656,
+ src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ }
+
+ /* Sets horizontal blanking delay and active lines */
+ cx18_av_write(cx, 0x470, hblank);
+ cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
+ (hactive << 4)));
+ cx18_av_write(cx, 0x472, hactive >> 4);
+
+ /* Sets burst gate delay */
+ cx18_av_write(cx, 0x473, burst);
+
+ /* Sets vertical blanking delay and active duration */
+ cx18_av_write(cx, 0x474, vblank);
+ cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
+ (vactive << 4)));
+ cx18_av_write(cx, 0x476, vactive >> 4);
+ cx18_av_write(cx, 0x477, vblank656);
+
+ /* Sets src decimation rate */
+ cx18_av_write(cx, 0x478, 0xff & src_decimation);
+ cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
+
+ /* Sets Luma and UV Low pass filters */
+ cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+ /* Enables comb filters */
+ cx18_av_write(cx, 0x47b, comb);
+
+ /* Sets SC Step*/
+ cx18_av_write(cx, 0x47c, sc);
+ cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
+ cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+
+ /* Sets VBI parameters */
+ if (std & V4L2_STD_625_50) {
+ cx18_av_write(cx, 0x47f, 0x01);
+ state->vbi_line_offset = 5;
+ } else {
+ cx18_av_write(cx, 0x47f, 0x00);
+ state->vbi_line_offset = 8;
+ }
+}
+
+int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_format *fmt;
+ struct v4l2_sliced_vbi_format *svbi;
+
+ switch (cmd) {
+ case VIDIOC_G_FMT:
+ {
+ static u16 lcr2vbi[] = {
+ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_WSS_625, 0, /* 4 */
+ V4L2_SLICED_CAPTION_525, /* 6 */
+ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+ 0, 0, 0, 0
+ };
+ int is_pal = !(state->std & V4L2_STD_525_60);
+ int i;
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ memset(svbi, 0, sizeof(*svbi));
+ /* we're done if raw VBI is active */
+ if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
+ break;
+
+ if (is_pal) {
+ for (i = 7; i <= 23; i++) {
+ u8 v = cx18_av_read(cx, 0x424 + i - 7);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |= svbi->service_lines[0][i] |
+ svbi->service_lines[1][i];
+ }
+ } else {
+ for (i = 10; i <= 21; i++) {
+ u8 v = cx18_av_read(cx, 0x424 + i - 10);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |= svbi->service_lines[0][i] |
+ svbi->service_lines[1][i];
+ }
+ }
+ break;
+ }
+
+ case VIDIOC_S_FMT:
+ {
+ int is_pal = !(state->std & V4L2_STD_525_60);
+ int vbi_offset = is_pal ? 1 : 0;
+ int i, x;
+ u8 lcr[24];
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ if (svbi->service_set == 0) {
+ /* raw VBI */
+ memset(svbi, 0, sizeof(*svbi));
+
+ /* Setup VBI */
+ cx18_av_vbi_setup(cx);
+
+ /* VBI Offset */
+ cx18_av_write(cx, 0x47f, vbi_offset);
+ cx18_av_write(cx, 0x404, 0x2e);
+ break;
+ }
+
+ for (x = 0; x <= 23; x++)
+ lcr[x] = 0x00;
+
+ /* Setup VBI */
+ cx18_av_vbi_setup(cx);
+
+ /* Sliced VBI */
+ cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
+ cx18_av_write(cx, 0x406, 0x13);
+ cx18_av_write(cx, 0x47f, vbi_offset);
+
+ if (is_pal) {
+ for (i = 0; i <= 6; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ } else {
+ for (i = 0; i <= 9; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+
+ for (i = 22; i <= 23; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ }
+
+ for (i = 7; i <= 23; i++) {
+ for (x = 0; x <= 1; x++) {
+ switch (svbi->service_lines[1-x][i]) {
+ case V4L2_SLICED_TELETEXT_B:
+ lcr[i] |= 1 << (4 * x);
+ break;
+ case V4L2_SLICED_WSS_625:
+ lcr[i] |= 4 << (4 * x);
+ break;
+ case V4L2_SLICED_CAPTION_525:
+ lcr[i] |= 6 << (4 * x);
+ break;
+ case V4L2_SLICED_VPS:
+ lcr[i] |= 9 << (4 * x);
+ break;
+ }
+ }
+ }
+
+ if (is_pal) {
+ for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+ cx18_av_write(cx, i, lcr[6 + x]);
+ } else {
+ for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+ cx18_av_write(cx, i, lcr[9 + x]);
+ for (i = 0x431; i <= 0x434; i++)
+ cx18_av_write(cx, i, 0);
+ }
+
+ cx18_av_write(cx, 0x43c, 0x16);
+ cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
+ break;
+ }
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ {
+ struct v4l2_decode_vbi_line *vbi = arg;
+ u8 *p = vbi->p;
+ int id1, id2, l, err = 0;
+
+ if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+ (p[3] != 0x55 && p[3] != 0x91)) {
+ vbi->line = vbi->type = 0;
+ break;
+ }
+
+ p += 4;
+ id1 = p[-1];
+ id2 = p[0] & 0xf;
+ l = p[2] & 0x3f;
+ l += state->vbi_line_offset;
+ p += 4;
+
+ switch (id2) {
+ case 1:
+ id2 = V4L2_SLICED_TELETEXT_B;
+ break;
+ case 4:
+ id2 = V4L2_SLICED_WSS_625;
+ break;
+ case 6:
+ id2 = V4L2_SLICED_CAPTION_525;
+ err = !odd_parity(p[0]) || !odd_parity(p[1]);
+ break;
+ case 9:
+ id2 = V4L2_SLICED_VPS;
+ if (decode_vps(p, p) != 0)
+ err = 1;
+ break;
+ default:
+ id2 = 0;
+ err = 1;
+ break;
+ }
+
+ vbi->type = err ? 0 : id2;
+ vbi->line = err ? 0 : l;
+ vbi->is_second_field = err ? 0 : (id1 == 0x55);
+ vbi->p = p;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c
new file mode 100644
index 000000000..c35eb53a3
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-cards.c
@@ -0,0 +1,281 @@
+/*
+ * cx18 functions to query card hardware
+ *
+ * Derived from ivtv-cards.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-av-core.h"
+#include "cx18-i2c.h"
+#include <media/cs5345.h>
+
+/********************** card configuration *******************************/
+
+/* usual i2c tuner addresses to probe */
+static struct cx18_card_tuner_i2c cx18_i2c_std = {
+ .radio = { I2C_CLIENT_END },
+ .demod = { 0x43, I2C_CLIENT_END },
+ .tv = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+ This keeps the PCI ID database up to date. Note that the entries
+ must be added under vendor 0x4444 (Conexant) as subsystem IDs.
+ New vendor IDs should still be added to the vendor ID list. */
+
+/* Hauppauge HVR-1600 cards */
+
+/* Note: for Hauppauge cards the tveeprom information is used instead
+ of PCI IDs */
+static const struct cx18_card cx18_card_hvr1600_esmt = {
+ .type = CX18_CARD_HVR_1600_ESMT,
+ .name = "Hauppauge HVR-1600",
+ .comment = "VBI is not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_muxer = CX18_HW_CS5345,
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
+ CX18_HW_CS5345 | CX18_HW_DVB,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+ { CX18_CARD_INPUT_LINE_IN2,
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX18_AV_AUDIO_SERIAL, 0 },
+ .ddr = {
+ /* ESMT M13S128324A-5B memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x44220e82,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 0,
+ },
+ .gpio_init.initial_value = 0x3001,
+ .gpio_init.direction = 0x3001,
+ .i2c = &cx18_i2c_std,
+};
+
+static const struct cx18_card cx18_card_hvr1600_samsung = {
+ .type = CX18_CARD_HVR_1600_SAMSUNG,
+ .name = "Hauppauge HVR-1600 (Preproduction)",
+ .comment = "VBI is not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_muxer = CX18_HW_CS5345,
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
+ CX18_HW_CS5345 | CX18_HW_DVB,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+ { CX18_CARD_INPUT_LINE_IN2,
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX18_AV_AUDIO_SERIAL, 0 },
+ .ddr = {
+ /* Samsung K4D263238G-VC33 memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x23230b73,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 2,
+ },
+ .gpio_init.initial_value = 0x3001,
+ .gpio_init.direction = 0x3001,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Compro VideoMate H900: note that this card is analog only! */
+
+static const struct cx18_card_pci_info cx18_pci_h900[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_h900 = {
+ .type = CX18_CARD_COMPRO_H900,
+ .name = "Compro VideoMate H900",
+ .comment = "VBI is not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_all = CX18_HW_TUNER,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX18_AV_AUDIO8, 0 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX18_AV_AUDIO_SERIAL, 0 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX18_AV_AUDIO_SERIAL, 0 },
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .ddr = {
+ /* EtronTech EM6A9160TS-5G memory */
+ .chip_config = 0x50003,
+ .refresh = 0x753,
+ .timing1 = 0x24330e84,
+ .timing2 = 0x1f,
+ .tune_lane = 0,
+ .initial_emrs = 0,
+ },
+ .xceive_pin = 15,
+ .pci_list = cx18_pci_h900,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPC718: not working at the moment! */
+
+static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_mpc718 = {
+ .type = CX18_CARD_YUAN_MPC718,
+ .name = "Yuan MPC718",
+ .comment = "Not yet supported!\n",
+ .v4l2_capabilities = 0,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_all = CX18_HW_TUNER,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX18_AV_AUDIO8, 0 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX18_AV_AUDIO_SERIAL, 0 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX18_AV_AUDIO_SERIAL, 0 },
+ .tuners = {
+ /* XC3028 tuner */
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .ddr = {
+ /* Probably Samsung K4D263238G-VC33 memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x23230b73,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 2,
+ },
+ .xceive_pin = 15,
+ .pci_list = cx18_pci_mpc718,
+ .i2c = &cx18_i2c_std,
+};
+
+static const struct cx18_card *cx18_card_list[] = {
+ &cx18_card_hvr1600_esmt,
+ &cx18_card_hvr1600_samsung,
+ &cx18_card_h900,
+ &cx18_card_mpc718,
+};
+
+const struct cx18_card *cx18_get_card(u16 index)
+{
+ if (index >= ARRAY_SIZE(cx18_card_list))
+ return NULL;
+ return cx18_card_list[index];
+}
+
+int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
+{
+ const struct cx18_card_video_input *card_input =
+ cx->card->video_inputs + index;
+ static const char * const input_strs[] = {
+ "Tuner 1",
+ "S-Video 1",
+ "S-Video 2",
+ "Composite 1",
+ "Composite 2",
+ "Composite 3"
+ };
+
+ memset(input, 0, sizeof(*input));
+ if (index >= cx->nof_inputs)
+ return -EINVAL;
+ input->index = index;
+ strlcpy(input->name, input_strs[card_input->video_type - 1],
+ sizeof(input->name));
+ input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ?
+ V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
+ input->audioset = (1 << cx->nof_audio_inputs) - 1;
+ input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ?
+ cx->tuner_std : V4L2_STD_ALL;
+ return 0;
+}
+
+int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio)
+{
+ const struct cx18_card_audio_input *aud_input =
+ cx->card->audio_inputs + index;
+ static const char * const input_strs[] = {
+ "Tuner 1",
+ "Line In 1",
+ "Line In 2"
+ };
+
+ memset(audio, 0, sizeof(*audio));
+ if (index >= cx->nof_audio_inputs)
+ return -EINVAL;
+ strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
+ sizeof(audio->name));
+ audio->index = index;
+ audio->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-cards.h b/linux/drivers/media/video/cx18/cx18-cards.h
new file mode 100644
index 000000000..3c2c0b929
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-cards.h
@@ -0,0 +1,131 @@
+/*
+ * cx18 functions to query card hardware
+ *
+ * Derived from ivtv-cards.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* hardware flags */
+#define CX18_HW_TUNER (1 << 0)
+#define CX18_HW_TVEEPROM (1 << 1)
+#define CX18_HW_CS5345 (1 << 2)
+#define CX18_HW_GPIO (1 << 3)
+#define CX18_HW_CX23418 (1 << 4)
+#define CX18_HW_DVB (1 << 5)
+
+/* video inputs */
+#define CX18_CARD_INPUT_VID_TUNER 1
+#define CX18_CARD_INPUT_SVIDEO1 2
+#define CX18_CARD_INPUT_SVIDEO2 3
+#define CX18_CARD_INPUT_COMPOSITE1 4
+#define CX18_CARD_INPUT_COMPOSITE2 5
+#define CX18_CARD_INPUT_COMPOSITE3 6
+
+/* audio inputs */
+#define CX18_CARD_INPUT_AUD_TUNER 1
+#define CX18_CARD_INPUT_LINE_IN1 2
+#define CX18_CARD_INPUT_LINE_IN2 3
+
+#define CX18_CARD_MAX_VIDEO_INPUTS 6
+#define CX18_CARD_MAX_AUDIO_INPUTS 3
+#define CX18_CARD_MAX_TUNERS 2
+
+/* V4L2 capability aliases */
+#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
+/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
+
+struct cx18_card_video_input {
+ u8 video_type; /* video input type */
+ u8 audio_index; /* index in cx18_card_audio_input array */
+ u16 video_input; /* hardware video input */
+};
+
+struct cx18_card_audio_input {
+ u8 audio_type; /* audio input type */
+ u32 audio_input; /* hardware audio input */
+ u16 muxer_input; /* hardware muxer input for boards with a
+ multiplexer chip */
+};
+
+struct cx18_card_pci_info {
+ u16 device;
+ u16 subsystem_vendor;
+ u16 subsystem_device;
+};
+
+/* GPIO definitions */
+
+/* The mask is the set of bits used by the operation */
+
+struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
+ u32 direction; /* DIR setting. Leave to 0 if no init is needed */
+ u32 initial_value;
+};
+
+struct cx18_card_tuner {
+ v4l2_std_id std; /* standard for which the tuner is suitable */
+ int tuner; /* tuner ID (from tuner.h) */
+};
+
+struct cx18_card_tuner_i2c {
+ unsigned short radio[2];/* radio tuner i2c address to probe */
+ unsigned short demod[2];/* demodulator i2c address to probe */
+ unsigned short tv[4]; /* tv tuner i2c addresses to probe */
+};
+
+struct cx18_ddr { /* DDR config data */
+ u32 chip_config;
+ u32 refresh;
+ u32 timing1;
+ u32 timing2;
+ u32 tune_lane;
+ u32 initial_emrs;
+};
+
+/* for card information/parameters */
+struct cx18_card {
+ int type;
+ char *name;
+ char *comment;
+ u32 v4l2_capabilities;
+ u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only
+ 1 dev allowed) */
+ u32 hw_muxer; /* hardware used to multiplex audio input */
+ u32 hw_all; /* all hardware used by the board */
+ struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS];
+ struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS];
+ struct cx18_card_audio_input radio_input;
+
+ /* GPIO card-specific settings */
+ u8 xceive_pin; /* XCeive tuner GPIO reset pin */
+ struct cx18_gpio_init gpio_init;
+
+ struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
+ struct cx18_card_tuner_i2c *i2c;
+
+ struct cx18_ddr ddr;
+
+ /* list of device and subsystem vendor/devices that
+ correspond to this card type. */
+ const struct cx18_card_pci_info *pci_list;
+};
+
+int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input);
+int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input);
+const struct cx18_card *cx18_get_card(u16 index);
diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c
new file mode 100644
index 000000000..87cf41021
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-controls.c
@@ -0,0 +1,306 @@
+/*
+ * cx18 ioctl control functions
+ *
+ * Derived from ivtv-controls.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-av-core.h"
+#include "cx18-cards.h"
+#include "cx18-ioctl.h"
+#include "cx18-audio.h"
+#include "cx18-i2c.h"
+#include "cx18-mailbox.h"
+#include "cx18-controls.h"
+
+static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_AUDIO_VOLUME,
+ V4L2_CID_AUDIO_BALANCE,
+ V4L2_CID_AUDIO_BASS,
+ V4L2_CID_AUDIO_TREBLE,
+ V4L2_CID_AUDIO_MUTE,
+ V4L2_CID_AUDIO_LOUDNESS,
+ 0
+};
+
+static const u32 *ctrl_classes[] = {
+ user_ctrls,
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
+{
+ const char *name;
+
+ CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
+
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ switch (qctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+ default:
+ if (cx2341x_ctrl_query(&cx->params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+ }
+ strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
+ qctrl->name[sizeof(qctrl->name) - 1] = 0;
+ return 0;
+}
+
+static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ cx18_queryctrl(cx, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+}
+
+static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
+ s32 v = vctrl->value;
+
+ CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
+
+ switch (vctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl);
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
+
+ default:
+ CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
+ CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
+
+ switch (vctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl);
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
+ default:
+ CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
+{
+ if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
+ return -EINVAL;
+ if (atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+
+ /* First try to allocate sliced VBI buffers if needed. */
+ if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
+ int i;
+
+ for (i = 0; i < CX18_VBI_FRAMES; i++) {
+ /* Yuck, hardcoded. Needs to be a define */
+ cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
+ if (cx->vbi.sliced_mpeg_data[i] == NULL) {
+ while (--i >= 0) {
+ kfree(cx->vbi.sliced_mpeg_data[i]);
+ cx->vbi.sliced_mpeg_data[i] = NULL;
+ }
+ return -ENOMEM;
+ }
+ }
+ }
+
+ cx->vbi.insert_mpeg = fmt;
+
+ if (cx->vbi.insert_mpeg == 0)
+ return 0;
+ /* Need sliced data for mpeg insertion */
+ if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
+ if (cx->is_60hz)
+ cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
+ else
+ cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
+ cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
+ }
+ return 0;
+}
+
+int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct v4l2_control ctrl;
+
+ switch (cmd) {
+ case VIDIOC_QUERYMENU:
+ CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
+ return cx18_querymenu(cx, arg);
+
+ case VIDIOC_QUERYCTRL:
+ return cx18_queryctrl(cx, arg);
+
+ case VIDIOC_S_CTRL:
+ return cx18_s_ctrl(cx, arg);
+
+ case VIDIOC_G_CTRL:
+ return cx18_g_ctrl(cx, arg);
+
+ case VIDIOC_S_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_s_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ struct cx2341x_mpeg_params p = cx->params;
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd);
+
+ if (err)
+ return err;
+
+ if (p.video_encoding != cx->params.video_encoding) {
+ int is_mpeg1 = p.video_encoding ==
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_format fmt;
+
+ /* fix videodecoder resolution */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
+ fmt.fmt.pix.height = cx->params.height;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
+ }
+ err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+ if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
+ err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+ cx->params = p;
+ cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+ cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
+ return err;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_g_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
+ return -EINVAL;
+ }
+
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params,
+ atomic_read(&cx->ana_capturing), arg, cmd);
+ return -EINVAL;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-controls.h b/linux/drivers/media/video/cx18/cx18-controls.h
new file mode 100644
index 000000000..6e985cf42
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-controls.h
@@ -0,0 +1,24 @@
+/*
+ * cx18 ioctl control functions
+ *
+ * Derived from ivtv-controls.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c
new file mode 100644
index 000000000..d9178843e
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-driver.c
@@ -0,0 +1,962 @@
+/*
+ * cx18 driver initialization and card probing
+ *
+ * Derived from ivtv-driver.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-version.h"
+#include "cx18-cards.h"
+#include "cx18-i2c.h"
+#include "cx18-irq.h"
+#include "cx18-gpio.h"
+#include "cx18-firmware.h"
+#include "cx18-streams.h"
+#include "cx18-av-core.h"
+#include "cx18-scb.h"
+#include "cx18-mailbox.h"
+#include "cx18-ioctl.h"
+#include "tuner-xc2028.h"
+
+#include <media/tveeprom.h>
+
+
+/* var to keep track of the number of array elements in use */
+int cx18_cards_active;
+
+/* If you have already X v4l cards, then set this to X. This way
+ the device numbers stay matched. Example: you have a WinTV card
+ without radio and a Compro H900 with. Normally this would give a
+ video1 device together with a radio0 device for the Compro. By
+ setting this to 1 you ensure that radio0 is now also radio1. */
+int cx18_first_minor;
+
+/* Master variable for all cx18 info */
+struct cx18 *cx18_cards[CX18_MAX_CARDS];
+
+/* Protects cx18_cards_active */
+DEFINE_SPINLOCK(cx18_cards_lock);
+
+/* add your revision and whatnot here */
+static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
+ {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
+
+/* Parameter declarations */
+static int cardtype[CX18_MAX_CARDS];
+static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+
+static int cardtype_c = 1;
+static int tuner_c = 1;
+static int radio_c = 1;
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+/* Buffers */
+static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
+static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
+static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
+static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
+
+static int cx18_pci_latency = 1;
+
+int cx18_debug;
+
+module_param_array(tuner, int, &tuner_c, 0644);
+module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(cardtype, int, &cardtype_c, 0644);
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
+module_param_named(debug, cx18_debug, int, 0644);
+module_param(cx18_pci_latency, int, 0644);
+module_param(cx18_first_minor, int, 0644);
+
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_ts_buffers, int, 0644);
+module_param(enc_yuv_buffers, int, 0644);
+module_param(enc_vbi_buffers, int, 0644);
+module_param(enc_pcm_buffers, int, 0644);
+
+MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
+ "\t\t\tsee tuner.h for values");
+MODULE_PARM_DESC(radio,
+ "Enable or disable the radio. Use only if autodetection\n"
+ "\t\t\tfails. 0 = disable, 1 = enable");
+MODULE_PARM_DESC(cardtype,
+ "Only use this option if your card is not detected properly.\n"
+ "\t\tSpecify card type:\n"
+ "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n"
+ "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
+ "\t\t\t 3 = Compro VideoMate H900\n"
+ "\t\t\t 4 = Yuan MPC718\n"
+ "\t\t\t 0 = Autodetect (default)\n"
+ "\t\t\t-1 = Ignore this card\n\t\t");
+MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
+MODULE_PARM_DESC(debug,
+ "Debug level (bitmask). Default: 0\n"
+ "\t\t\t 1/0x0001: warning\n"
+ "\t\t\t 2/0x0002: info\n"
+ "\t\t\t 4/0x0004: mailbox\n"
+ "\t\t\t 8/0x0008: dma\n"
+ "\t\t\t 16/0x0010: ioctl\n"
+ "\t\t\t 32/0x0020: file\n"
+ "\t\t\t 64/0x0040: i2c\n"
+ "\t\t\t128/0x0080: irq\n"
+ "\t\t\t256/0x0100: high volume\n");
+MODULE_PARM_DESC(cx18_pci_latency,
+ "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
+ "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(enc_mpg_buffers,
+ "Encoder MPG Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_ts_buffers,
+ "Encoder TS Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_buffers,
+ "Encoder YUV Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_buffers,
+ "Encoder VBI Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_buffers,
+ "Encoder PCM buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
+
+MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card");
+
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("CX23418 driver");
+MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(CX18_VERSION);
+
+/* Generic utility functions */
+int cx18_msleep_timeout(unsigned int msecs, int intr)
+{
+ int timeout = msecs_to_jiffies(msecs);
+ int sig;
+
+ do {
+ set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+ timeout = schedule_timeout(timeout);
+ sig = intr ? signal_pending(current) : 0;
+ } while (!sig && timeout);
+ return sig;
+}
+
+/* Release ioremapped memory */
+static void cx18_iounmap(struct cx18 *cx)
+{
+ if (cx == NULL)
+ return;
+
+ /* Release io memory */
+ if (cx->enc_mem != NULL) {
+ CX18_DEBUG_INFO("releasing enc_mem\n");
+ iounmap(cx->enc_mem);
+ cx->enc_mem = NULL;
+ }
+}
+
+/* Hauppauge card? get values from tveeprom */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
+{
+ u8 eedata[256];
+
+ cx->i2c_client[0].addr = 0xA0 >> 1;
+ tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata));
+ tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata);
+}
+
+static void cx18_process_eeprom(struct cx18 *cx)
+{
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+
+ /* Many thanks to Steven Toth from Hauppauge for providing the
+ model numbers */
+ /* Note: the Samsung memory models cannot be reliably determined
+ from the model number. Use the cardtype module option if you
+ have one of these preproduction models. */
+ switch (tv.model) {
+ case 74000 ... 74999:
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ break;
+ case 0:
+ CX18_ERR("Invalid EEPROM\n");
+ return;
+ default:
+ CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model);
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ break;
+ }
+
+ cx->v4l2_cap = cx->card->v4l2_capabilities;
+ cx->card_name = cx->card->name;
+ cx->card_i2c = cx->card->i2c;
+
+ CX18_INFO("Autodetected %s\n", cx->card_name);
+
+ if (tv.tuner_type == TUNER_ABSENT)
+ CX18_ERR("tveeprom cannot autodetect tuner!");
+
+ if (cx->options.tuner == -1)
+ cx->options.tuner = tv.tuner_type;
+ if (cx->options.radio == -1)
+ cx->options.radio = (tv.has_radio != 0);
+
+ if (cx->std != 0)
+ /* user specified tuner standard */
+ return;
+
+ /* autodetect tuner standard */
+ if (tv.tuner_formats & V4L2_STD_PAL) {
+ CX18_DEBUG_INFO("PAL tuner detected\n");
+ cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+ } else if (tv.tuner_formats & V4L2_STD_NTSC) {
+ CX18_DEBUG_INFO("NTSC tuner detected\n");
+ cx->std |= V4L2_STD_NTSC_M;
+ } else if (tv.tuner_formats & V4L2_STD_SECAM) {
+ CX18_DEBUG_INFO("SECAM tuner detected\n");
+ cx->std |= V4L2_STD_SECAM_L;
+ } else {
+ CX18_INFO("No tuner detected, default to NTSC-M\n");
+ cx->std |= V4L2_STD_NTSC_M;
+ }
+}
+
+static v4l2_std_id cx18_parse_std(struct cx18 *cx)
+{
+ switch (pal[0]) {
+ case '6':
+ return V4L2_STD_PAL_60;
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ return V4L2_STD_PAL_BG;
+ case 'h':
+ case 'H':
+ return V4L2_STD_PAL_H;
+ case 'n':
+ case 'N':
+ if (pal[1] == 'c' || pal[1] == 'C')
+ return V4L2_STD_PAL_Nc;
+ return V4L2_STD_PAL_N;
+ case 'i':
+ case 'I':
+ return V4L2_STD_PAL_I;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ return V4L2_STD_PAL_DK;
+ case 'M':
+ case 'm':
+ return V4L2_STD_PAL_M;
+ case '-':
+ break;
+ default:
+ CX18_WARN("pal= argument not recognised\n");
+ return 0;
+ }
+
+ switch (secam[0]) {
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ case 'h':
+ case 'H':
+ return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ return V4L2_STD_SECAM_DK;
+ case 'l':
+ case 'L':
+ if (secam[1] == 'C' || secam[1] == 'c')
+ return V4L2_STD_SECAM_LC;
+ return V4L2_STD_SECAM_L;
+ case '-':
+ break;
+ default:
+ CX18_WARN("secam= argument not recognised\n");
+ return 0;
+ }
+
+ switch (ntsc[0]) {
+ case 'm':
+ case 'M':
+ return V4L2_STD_NTSC_M;
+ case 'j':
+ case 'J':
+ return V4L2_STD_NTSC_M_JP;
+ case 'k':
+ case 'K':
+ return V4L2_STD_NTSC_M_KR;
+ case '-':
+ break;
+ default:
+ CX18_WARN("ntsc= argument not recognised\n");
+ return 0;
+ }
+
+ /* no match found */
+ return 0;
+}
+
+static void cx18_process_options(struct cx18 *cx)
+{
+ int i, j;
+
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+ cx->options.cardtype = cardtype[cx->num];
+ cx->options.tuner = tuner[cx->num];
+ cx->options.radio = radio[cx->num];
+
+ cx->std = cx18_parse_std(cx);
+ if (cx->options.cardtype == -1) {
+ CX18_INFO("Ignore card\n");
+ return;
+ }
+ cx->card = cx18_get_card(cx->options.cardtype - 1);
+ if (cx->card)
+ CX18_INFO("User specified %s card\n", cx->card->name);
+ else if (cx->options.cardtype != 0)
+ CX18_ERR("Unknown user specified type, trying to autodetect card\n");
+ if (cx->card == NULL) {
+ if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_INFO("Autodetected Hauppauge card\n");
+ }
+ }
+ if (cx->card == NULL) {
+ for (i = 0; (cx->card = cx18_get_card(i)); i++) {
+ if (cx->card->pci_list == NULL)
+ continue;
+ for (j = 0; cx->card->pci_list[j].device; j++) {
+ if (cx->dev->device !=
+ cx->card->pci_list[j].device)
+ continue;
+ if (cx->dev->subsystem_vendor !=
+ cx->card->pci_list[j].subsystem_vendor)
+ continue;
+ if (cx->dev->subsystem_device !=
+ cx->card->pci_list[j].subsystem_device)
+ continue;
+ CX18_INFO("Autodetected %s card\n", cx->card->name);
+ goto done;
+ }
+ }
+ }
+done:
+
+ if (cx->card == NULL) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_ERR("Unknown card: vendor/device: %04x/%04x\n",
+ cx->dev->vendor, cx->dev->device);
+ CX18_ERR(" subsystem vendor/device: %04x/%04x\n",
+ cx->dev->subsystem_vendor, cx->dev->subsystem_device);
+ CX18_ERR("Defaulting to %s card\n", cx->card->name);
+ CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+ CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+ CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n");
+ }
+ cx->v4l2_cap = cx->card->v4l2_capabilities;
+ cx->card_name = cx->card->name;
+ cx->card_i2c = cx->card->i2c;
+}
+
+/* Precondition: the cx18 structure has been memset to 0. Only
+ the dev and num fields have been filled in.
+ No assumptions on the card type may be made here (see cx18_init_struct2
+ for that).
+ */
+static int __devinit cx18_init_struct1(struct cx18 *cx)
+{
+ cx->base_addr = pci_resource_start(cx->dev, 0);
+
+ mutex_init(&cx->serialize_lock);
+ mutex_init(&cx->i2c_bus_lock[0]);
+ mutex_init(&cx->i2c_bus_lock[1]);
+
+ spin_lock_init(&cx->lock);
+ spin_lock_init(&cx->dma_reg_lock);
+
+ /* start counting open_id at 1 */
+ cx->open_id = 1;
+
+ /* Initial settings */
+ cx2341x_fill_defaults(&cx->params);
+ cx->temporal_strength = cx->params.video_temporal_filter;
+ cx->spatial_strength = cx->params.video_spatial_filter;
+ cx->filter_mode = cx->params.video_spatial_filter_mode |
+ (cx->params.video_temporal_filter_mode << 1) |
+ (cx->params.video_median_filter_type << 2);
+ cx->params.port = CX2341X_PORT_MEMORY;
+ cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+ init_waitqueue_head(&cx->cap_w);
+ init_waitqueue_head(&cx->mb_apu_waitq);
+ init_waitqueue_head(&cx->mb_cpu_waitq);
+ init_waitqueue_head(&cx->mb_epu_waitq);
+ init_waitqueue_head(&cx->mb_hpu_waitq);
+ init_waitqueue_head(&cx->dma_waitq);
+
+ /* VBI */
+ cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
+ cx->vbi.raw_size = 1456;
+ cx->vbi.raw_decoder_line_size = 1456;
+ cx->vbi.raw_decoder_sav_odd_field = 0x20;
+ cx->vbi.raw_decoder_sav_even_field = 0x60;
+ cx->vbi.sliced_decoder_line_size = 272;
+ cx->vbi.sliced_decoder_sav_odd_field = 0xB0;
+ cx->vbi.sliced_decoder_sav_even_field = 0xF0;
+ return 0;
+}
+
+/* Second initialization part. Here the card type has been
+ autodetected. */
+static void __devinit cx18_init_struct2(struct cx18 *cx)
+{
+ int i;
+
+ for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
+ if (cx->card->video_inputs[i].video_type == 0)
+ break;
+ cx->nof_inputs = i;
+ for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
+ if (cx->card->audio_inputs[i].audio_type == 0)
+ break;
+ cx->nof_audio_inputs = i;
+
+ /* Find tuner input */
+ for (i = 0; i < cx->nof_inputs; i++) {
+ if (cx->card->video_inputs[i].video_type ==
+ CX18_CARD_INPUT_VID_TUNER)
+ break;
+ }
+ if (i == cx->nof_inputs)
+ i = 0;
+ cx->active_input = i;
+ cx->audio_input = cx->card->video_inputs[i].audio_index;
+ cx->av_state.vid_input = CX18_AV_COMPOSITE7;
+ cx->av_state.aud_input = CX18_AV_AUDIO8;
+ cx->av_state.audclk_freq = 48000;
+ cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
+ cx->av_state.vbi_line_offset = 8;
+}
+
+static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
+ const struct pci_device_id *pci_id)
+{
+ u16 cmd;
+ unsigned char pci_latency;
+
+ CX18_DEBUG_INFO("Enabling pci device\n");
+
+ if (pci_enable_device(dev)) {
+ CX18_ERR("Can't enable device %d!\n", cx->num);
+ return -EIO;
+ }
+ if (pci_set_dma_mask(dev, 0xffffffff)) {
+ CX18_ERR("No suitable DMA available on card %d.\n", cx->num);
+ return -EIO;
+ }
+ if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
+ CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num);
+ return -EIO;
+ }
+
+ /* Check for bus mastering */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+
+ if (pci_latency < 64 && cx18_pci_latency) {
+ CX18_INFO("Unreasonably low latency timer, "
+ "setting to 64 (was %d)\n", pci_latency);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+ }
+ /* This config space value relates to DMA latencies. The
+ default value 0x8080 is too low however and will lead
+ to DMA errors. 0xffff is the max value which solves
+ these problems. */
+ pci_write_config_dword(dev, 0x40, 0xffff);
+
+ CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
+ "irq: %d, latency: %d, memory: 0x%lx\n",
+ cx->dev->device, cx->card_rev, dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ cx->dev->irq, pci_latency, (unsigned long)cx->base_addr);
+
+ return 0;
+}
+
+#ifdef MODULE
+static u32 cx18_request_module(struct cx18 *cx, u32 hw,
+ const char *name, u32 id)
+{
+ if ((hw & id) == 0)
+ return hw;
+ if (request_module(name) != 0) {
+ CX18_ERR("Failed to load module %s\n", name);
+ return hw & ~id;
+ }
+ CX18_DEBUG_INFO("Loaded module %s\n", name);
+ return hw;
+}
+#endif
+
+static void cx18_load_and_init_modules(struct cx18 *cx)
+{
+ u32 hw = cx->card->hw_all;
+ int i;
+
+#ifdef MODULE
+ /* load modules */
+#ifndef CONFIG_MEDIA_TUNER
+ hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER);
+#endif
+#ifndef CONFIG_VIDEO_CS5345
+ hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345);
+#endif
+#endif
+
+ /* check which i2c devices are actually found */
+ for (i = 0; i < 32; i++) {
+ u32 device = 1 << i;
+
+ if (!(device & hw))
+ continue;
+ if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM ||
+ device == CX18_HW_CX23418 || device == CX18_HW_DVB) {
+ /* These 'devices' do not use i2c probing */
+ cx->hw_flags |= device;
+ continue;
+ }
+ cx18_i2c_register(cx, i);
+ if (cx18_i2c_hw_addr(cx, device) > 0)
+ cx->hw_flags |= device;
+ }
+
+ hw = cx->hw_flags;
+}
+
+static int __devinit cx18_probe(struct pci_dev *dev,
+ const struct pci_device_id *pci_id)
+{
+ int retval = 0;
+ int vbi_buf_size;
+ u32 devtype;
+ struct cx18 *cx;
+
+ spin_lock(&cx18_cards_lock);
+
+ /* Make sure we've got a place for this card */
+ if (cx18_cards_active == CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n",
+ cx18_cards_active);
+ spin_unlock(&cx18_cards_lock);
+ return -ENOMEM;
+ }
+
+ cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
+ if (!cx) {
+ spin_unlock(&cx18_cards_lock);
+ return -ENOMEM;
+ }
+ cx18_cards[cx18_cards_active] = cx;
+ cx->dev = dev;
+ cx->num = cx18_cards_active++;
+ snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num);
+ CX18_INFO("Initializing card #%d\n", cx->num);
+
+ spin_unlock(&cx18_cards_lock);
+
+ cx18_process_options(cx);
+ if (cx->options.cardtype == -1) {
+ retval = -ENODEV;
+ goto err;
+ }
+ if (cx18_init_struct1(cx)) {
+ retval = -ENOMEM;
+ goto err;
+ }
+
+ CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
+
+ /* PCI Device Setup */
+ retval = cx18_setup_pci(cx, dev, pci_id);
+ if (retval != 0) {
+ if (retval == -EIO)
+ goto free_workqueue;
+ else if (retval == -ENXIO)
+ goto free_mem;
+ }
+ /* save cx in the pci struct for later use */
+ pci_set_drvdata(dev, cx);
+
+ /* map io memory */
+ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
+ cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
+ cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
+ CX18_MEM_SIZE);
+ if (!cx->enc_mem) {
+ CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
+ CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ retval = -ENOMEM;
+ goto free_mem;
+ }
+ cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
+ devtype = read_reg(0xC72028);
+ switch (devtype & 0xff000000) {
+ case 0xff000000:
+ CX18_INFO("cx23418 revision %08x (A)\n", devtype);
+ break;
+ case 0x01000000:
+ CX18_INFO("cx23418 revision %08x (B)\n", devtype);
+ break;
+ default:
+ CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype);
+ break;
+ }
+
+ cx18_init_power(cx, 1);
+ cx18_init_memory(cx);
+
+ cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET);
+ cx18_init_scb(cx);
+
+ cx18_gpio_init(cx);
+
+ /* active i2c */
+ CX18_DEBUG_INFO("activating i2c...\n");
+ if (init_cx18_i2c(cx)) {
+ CX18_ERR("Could not initialize i2c\n");
+ goto free_map;
+ }
+
+ CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active);
+
+ if (cx->card->hw_all & CX18_HW_TVEEPROM) {
+ /* Based on the model number the cardtype may be changed.
+ The PCI IDs are not always reliable. */
+ cx18_process_eeprom(cx);
+ }
+ if (cx->card->comment)
+ CX18_INFO("%s", cx->card->comment);
+ if (cx->card->v4l2_capabilities == 0) {
+ retval = -ENODEV;
+ goto free_i2c;
+ }
+ cx18_init_memory(cx);
+
+ /* Register IRQ */
+ retval = request_irq(cx->dev->irq, cx18_irq_handler,
+ IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx);
+ if (retval) {
+ CX18_ERR("Failed to register irq %d\n", retval);
+ goto free_i2c;
+ }
+
+ if (cx->std == 0)
+ cx->std = V4L2_STD_NTSC_M;
+
+ if (cx->options.tuner == -1) {
+ int i;
+
+ for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
+ if ((cx->std & cx->card->tuners[i].std) == 0)
+ continue;
+ cx->options.tuner = cx->card->tuners[i].tuner;
+ break;
+ }
+ }
+ /* if no tuner was found, then pick the first tuner in the card list */
+ if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
+ cx->std = cx->card->tuners[0].std;
+ cx->options.tuner = cx->card->tuners[0].tuner;
+ }
+ if (cx->options.radio == -1)
+ cx->options.radio = (cx->card->radio_input.audio_type != 0);
+
+ /* The card is now fully identified, continue with card-specific
+ initialization. */
+ cx18_init_struct2(cx);
+
+ cx18_load_and_init_modules(cx);
+
+ if (cx->std & V4L2_STD_525_60) {
+ cx->is_60hz = 1;
+ cx->is_out_60hz = 1;
+ } else {
+ cx->is_50hz = 1;
+ cx->is_out_50hz = 1;
+ }
+ cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
+
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000;
+ vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
+
+ if (cx->options.radio > 0)
+ cx->v4l2_cap |= V4L2_CAP_RADIO;
+
+ if (cx->options.tuner > -1) {
+ struct tuner_setup setup;
+
+ setup.addr = ADDR_UNSET;
+ setup.type = cx->options.tuner;
+ setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
+ setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+ cx18_reset_tuner_gpio : NULL;
+ cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup);
+ if (setup.type == TUNER_XC2028) {
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ };
+ struct v4l2_priv_tun_config cfg = {
+ .tuner = cx->options.tuner,
+ .priv = &ctrl,
+ };
+ cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg);
+ }
+ }
+
+ /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
+ are not. */
+ cx->tuner_std = cx->std;
+
+ retval = cx18_streams_setup(cx);
+ if (retval) {
+ CX18_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
+ }
+ retval = cx18_streams_register(cx);
+ if (retval) {
+ CX18_ERR("Error %d registering devices\n", retval);
+ goto free_streams;
+ }
+
+ CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
+
+ return 0;
+
+free_streams:
+ cx18_streams_cleanup(cx, 1);
+free_irq:
+ free_irq(cx->dev->irq, (void *)cx);
+free_i2c:
+ exit_cx18_i2c(cx);
+free_map:
+ cx18_iounmap(cx);
+free_mem:
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+free_workqueue:
+err:
+ if (retval == 0)
+ retval = -ENODEV;
+ CX18_ERR("Error %d on initialization\n", retval);
+
+ kfree(cx18_cards[cx18_cards_active]);
+ cx18_cards[cx18_cards_active] = NULL;
+ return retval;
+}
+
+int cx18_init_on_first_open(struct cx18 *cx)
+{
+ int video_input;
+ int fw_retry_count = 3;
+ struct v4l2_frequency vf;
+
+ if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
+ return -ENXIO;
+
+ if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags))
+ return 0;
+
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (cx18_firmware_init(cx) == 0)
+ break;
+ if (fw_retry_count > 1)
+ CX18_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(CX18_F_I_FAILED, &cx->i_flags);
+ return -ENXIO;
+ }
+ set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
+
+ /* Init the firmware twice to work around a silicon bug
+ * transport related. */
+
+ fw_retry_count = 3;
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (cx18_firmware_init(cx) == 0)
+ break;
+ if (fw_retry_count > 1)
+ CX18_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(CX18_F_I_FAILED, &cx->i_flags);
+ return -ENXIO;
+ }
+
+ vf.tuner = 0;
+ vf.type = V4L2_TUNER_ANALOG_TV;
+ vf.frequency = 6400; /* the tuner 'baseline' frequency */
+
+ /* Set initial frequency. For PAL/SECAM broadcasts no
+ 'default' channel exists AFAIK. */
+ if (cx->std == V4L2_STD_NTSC_M_JP)
+ vf.frequency = 1460; /* ch. 1 91250*16/1000 */
+ else if (cx->std & V4L2_STD_NTSC_M)
+ vf.frequency = 1076; /* ch. 4 67250*16/1000 */
+
+ video_input = cx->active_input;
+ cx->active_input++; /* Force update of input */
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
+
+ /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+ in one place. */
+ cx->std++; /* Force full standard initialization */
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
+ return 0;
+}
+
+static void cx18_remove(struct pci_dev *pci_dev)
+{
+ struct cx18 *cx = pci_get_drvdata(pci_dev);
+
+ CX18_DEBUG_INFO("Removing Card #%d\n", cx->num);
+
+ /* Stop all captures */
+ CX18_DEBUG_INFO("Stopping all streams\n");
+ if (atomic_read(&cx->tot_capturing) > 0)
+ cx18_stop_all_captures(cx);
+
+ /* Interrupts */
+ sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+ sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ cx18_halt_firmware(cx);
+
+ cx18_streams_cleanup(cx, 1);
+
+ exit_cx18_i2c(cx);
+
+ free_irq(cx->dev->irq, (void *)cx);
+
+ cx18_iounmap(cx);
+
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+
+ pci_disable_device(cx->dev);
+
+ CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
+}
+
+/* define a pci_driver for card detection */
+static struct pci_driver cx18_pci_driver = {
+ .name = "cx18",
+ .id_table = cx18_pci_tbl,
+ .probe = cx18_probe,
+ .remove = cx18_remove,
+};
+
+static int module_start(void)
+{
+ printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
+
+ memset(cx18_cards, 0, sizeof(cx18_cards));
+
+ /* Validate parameters */
+ if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n",
+ CX18_MAX_CARDS - 1);
+ return -1;
+ }
+
+ if (cx18_debug < 0 || cx18_debug > 511) {
+ cx18_debug = 0;
+ printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
+ }
+
+ if (pci_register_driver(&cx18_pci_driver)) {
+ printk(KERN_ERR "cx18: Error detecting PCI card\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO "cx18: End initialization\n");
+ return 0;
+}
+
+static void module_cleanup(void)
+{
+ int i;
+
+ pci_unregister_driver(&cx18_pci_driver);
+
+ for (i = 0; i < cx18_cards_active; i++) {
+ if (cx18_cards[i] == NULL)
+ continue;
+ kfree(cx18_cards[i]);
+ }
+}
+
+module_init(module_start);
+module_exit(module_cleanup);
diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h
new file mode 100644
index 000000000..576358873
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-driver.h
@@ -0,0 +1,516 @@
+/*
+ * cx18 driver internal defines and structures
+ *
+ * Derived from ivtv-driver.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef CX18_DRIVER_H
+#define CX18_DRIVER_H
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <linux/byteorder/swab.h>
+#include <linux/pagemap.h>
+#include <linux/workqueue.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+#include <linux/mutex.h>
+#endif
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include "cx18-mailbox.h"
+#include "cx18-av-core.h"
+#include "cx23418.h"
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#ifndef CONFIG_PCI
+# error "This driver requires kernel PCI support."
+#endif
+
+#define CX18_MEM_OFFSET 0x00000000
+#define CX18_MEM_SIZE 0x04000000
+#define CX18_REG_OFFSET 0x02000000
+
+/* Maximum cx18 driver instances. */
+#define CX18_MAX_CARDS 32
+
+/* Supported cards */
+#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */
+#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */
+#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */
+#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
+#define CX18_CARD_LAST 3
+
+#define CX18_ENC_STREAM_TYPE_MPG 0
+#define CX18_ENC_STREAM_TYPE_TS 1
+#define CX18_ENC_STREAM_TYPE_YUV 2
+#define CX18_ENC_STREAM_TYPE_VBI 3
+#define CX18_ENC_STREAM_TYPE_PCM 4
+#define CX18_ENC_STREAM_TYPE_IDX 5
+#define CX18_ENC_STREAM_TYPE_RAD 6
+#define CX18_MAX_STREAMS 7
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_CX 0x14f1
+#define PCI_DEVICE_ID_CX23418 0x5b7a
+
+/* subsystem vendor ID */
+#define CX18_PCI_ID_HAUPPAUGE 0x0070
+#define CX18_PCI_ID_COMPRO 0x185b
+#define CX18_PCI_ID_YUAN 0x12ab
+
+/* ======================================================================== */
+/* ========================== START USER SETTABLE DMA VARIABLES =========== */
+/* ======================================================================== */
+
+/* DMA Buffers, Default size in MB allocated */
+#define CX18_DEFAULT_ENC_TS_BUFFERS 1
+#define CX18_DEFAULT_ENC_MPG_BUFFERS 2
+#define CX18_DEFAULT_ENC_IDX_BUFFERS 1
+#define CX18_DEFAULT_ENC_YUV_BUFFERS 2
+#define CX18_DEFAULT_ENC_VBI_BUFFERS 1
+#define CX18_DEFAULT_ENC_PCM_BUFFERS 1
+
+/* i2c stuff */
+#define I2C_CLIENTS_MAX 16
+
+/* debugging */
+
+/* Flag to turn on high volume debugging */
+#define CX18_DBGFLG_WARN (1 << 0)
+#define CX18_DBGFLG_INFO (1 << 1)
+#define CX18_DBGFLG_API (1 << 2)
+#define CX18_DBGFLG_DMA (1 << 3)
+#define CX18_DBGFLG_IOCTL (1 << 4)
+#define CX18_DBGFLG_FILE (1 << 5)
+#define CX18_DBGFLG_I2C (1 << 6)
+#define CX18_DBGFLG_IRQ (1 << 7)
+/* Flag to turn on high volume debugging */
+#define CX18_DBGFLG_HIGHVOL (1 << 8)
+
+/* NOTE: extra space before comma in 'cx->num , ## args' is required for
+ gcc-2.95, otherwise it won't compile. */
+#define CX18_DEBUG(x, type, fmt, args...) \
+ do { \
+ if ((x) & cx18_debug) \
+ printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \
+ } while (0)
+#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args)
+#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args)
+#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args)
+#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args)
+#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
+#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+ do { \
+ if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
+ printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \
+ } while (0)
+#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args)
+#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args)
+#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args)
+#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args)
+#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
+#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+/* Standard kernel messages */
+#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args)
+#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args)
+#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args)
+
+/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
+#define MPEG_FRAME_TYPE_IFRAME 1
+#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
+#define MPEG_FRAME_TYPE_ALL 7
+
+#define CX18_MAX_PGM_INDEX (400)
+
+extern int cx18_debug;
+
+
+struct cx18_options {
+ int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */
+ int cardtype; /* force card type on load */
+ int tuner; /* set tuner on load */
+ int radio; /* enable/disable radio */
+};
+
+/* per-buffer bit flags */
+#define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */
+
+/* per-stream, s_flags */
+#define CX18_F_S_CLAIMED 3 /* this stream is claimed */
+#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */
+#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */
+#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */
+#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */
+
+/* per-cx18, i_flags */
+#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */
+#define CX18_F_I_EOS 4 /* End of encoder stream reached */
+#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */
+#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */
+#define CX18_F_I_INITED 21 /* set after first open */
+#define CX18_F_I_FAILED 22 /* set if first open failed */
+
+/* These are the VBI types as they appear in the embedded VBI private packets. */
+#define CX18_SLICED_TYPE_TELETEXT_B (1)
+#define CX18_SLICED_TYPE_CAPTION_525 (4)
+#define CX18_SLICED_TYPE_WSS_625 (5)
+#define CX18_SLICED_TYPE_VPS (7)
+
+struct cx18_buffer {
+ struct list_head list;
+ dma_addr_t dma_handle;
+ u32 id;
+ unsigned long b_flags;
+ char *buf;
+
+ u32 bytesused;
+ u32 readpos;
+};
+
+struct cx18_queue {
+ struct list_head list;
+ u32 buffers;
+ u32 length;
+ u32 bytesused;
+};
+
+struct cx18_dvb {
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ struct dmxdev dmxdev;
+ struct dvb_adapter dvb_adapter;
+ struct dvb_demux demux;
+ struct dvb_frontend *fe;
+ struct dvb_net dvbnet;
+ int enabled;
+ int feeding;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex feedlock;
+#else
+ struct semaphore feedlock;
+#endif
+
+};
+
+struct cx18; /* forward reference */
+struct cx18_scb; /* forward reference */
+
+struct cx18_stream {
+ /* These first four fields are always set, even if the stream
+ is not actually created. */
+ struct video_device *v4l2dev; /* NULL when stream not created */
+ struct cx18 *cx; /* for ease of use */
+ const char *name; /* name of the stream */
+ int type; /* stream type */
+ u32 handle; /* task handle */
+ unsigned mdl_offset;
+
+ u32 id;
+ spinlock_t qlock; /* locks access to the queues */
+ unsigned long s_flags; /* status flags, see above */
+ int dma; /* can be PCI_DMA_TODEVICE,
+ PCI_DMA_FROMDEVICE or
+ PCI_DMA_NONE */
+ u64 dma_pts;
+ wait_queue_head_t waitq;
+
+ /* Buffer Stats */
+ u32 buffers;
+ u32 buf_size;
+ u32 buffers_stolen;
+
+ /* Buffer Queues */
+ struct cx18_queue q_free; /* free buffers */
+ struct cx18_queue q_full; /* full buffers */
+ struct cx18_queue q_io; /* waiting for I/O */
+
+ /* DVB / Digital Transport */
+ struct cx18_dvb dvb;
+};
+
+struct cx18_open_id {
+ u32 open_id;
+ int type;
+ enum v4l2_priority prio;
+ struct cx18 *cx;
+};
+
+/* forward declaration of struct defined in cx18-cards.h */
+struct cx18_card;
+
+
+#define CX18_VBI_FRAMES 32
+
+/* VBI data */
+struct vbi_info {
+ u32 enc_size;
+ u32 frame;
+ u8 cc_data_odd[256];
+ u8 cc_data_even[256];
+ int cc_pos;
+ u8 cc_no_update;
+ u8 vps[5];
+ u8 vps_found;
+ int wss;
+ u8 wss_found;
+ u8 wss_no_update;
+ u32 raw_decoder_line_size;
+ u8 raw_decoder_sav_odd_field;
+ u8 raw_decoder_sav_even_field;
+ u32 sliced_decoder_line_size;
+ u8 sliced_decoder_sav_odd_field;
+ u8 sliced_decoder_sav_even_field;
+ struct v4l2_format in;
+ /* convenience pointer to sliced struct in vbi_in union */
+ struct v4l2_sliced_vbi_format *sliced_in;
+ u32 service_set_in;
+ int insert_mpeg;
+
+ /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+ One for /dev/vbi0 and one for /dev/vbi8 */
+ struct v4l2_sliced_vbi_data sliced_data[36];
+
+ /* Buffer for VBI data inserted into MPEG stream.
+ The first byte is a dummy byte that's never used.
+ The next 16 bytes contain the MPEG header for the VBI data,
+ the remainder is the actual VBI data.
+ The max size accepted by the MPEG VBI reinsertion turns out
+ to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
+ where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
+ a single line header byte and 2 * 18 is the number of VBI lines per frame.
+
+ However, it seems that the data must be 1K aligned, so we have to
+ pad the data until the 1 or 2 K boundary.
+
+ This pointer array will allocate 2049 bytes to store each VBI frame. */
+ u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
+ u32 sliced_mpeg_size[CX18_VBI_FRAMES];
+ struct cx18_buffer sliced_mpeg_buf;
+ u32 inserted_frame;
+
+ u32 start[2], count;
+ u32 raw_size;
+ u32 sliced_size;
+};
+
+/* Per cx23418, per I2C bus private algo callback data */
+struct cx18_i2c_algo_callback_data {
+ struct cx18 *cx;
+ int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */
+};
+
+/* Struct to hold info about cx18 cards */
+struct cx18 {
+ int num; /* board number, -1 during init! */
+ char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */
+ struct pci_dev *dev; /* PCI device */
+ const struct cx18_card *card; /* card information */
+ const char *card_name; /* full name of the card */
+ const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
+ u8 is_50hz;
+ u8 is_60hz;
+ u8 is_out_50hz;
+ u8 is_out_60hz;
+ u8 nof_inputs; /* number of video inputs */
+ u8 nof_audio_inputs; /* number of audio inputs */
+ u16 buffer_id; /* buffer ID counter */
+ u32 v4l2_cap; /* V4L2 capabilities of card */
+ u32 hw_flags; /* Hardware description of the board */
+ unsigned mdl_offset;
+ struct cx18_scb __iomem *scb; /* pointer to SCB */
+
+ struct cx18_av_state av_state;
+
+ /* codec settings */
+ struct cx2341x_mpeg_params params;
+ u32 filter_mode;
+ u32 temporal_strength;
+ u32 spatial_strength;
+
+ /* dualwatch */
+ unsigned long dualwatch_jiffies;
+ u16 dualwatch_stereo_mode;
+
+ /* Digitizer type */
+ int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
+#else
+ struct semaphore serialize_lock;/* mutex used to serialize open/close/start/stop/ioctl operations */
+#endif
+ struct cx18_options options; /* User options */
+ int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
+ struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
+ unsigned long i_flags; /* global cx18 flags */
+ atomic_t ana_capturing; /* count number of active analog capture streams */
+ atomic_t tot_capturing; /* total count number of active capture streams */
+ spinlock_t lock; /* lock access to this struct */
+ int search_pack_header;
+
+ spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+
+ int open_id; /* incremented each time an open occurs, used as
+ unique ID. Starts at 1, so 0 can be used as
+ uninitialized value in the stream->id. */
+
+ u32 base_addr;
+ struct v4l2_prio_state prio;
+
+ u8 card_rev;
+ void __iomem *enc_mem, *reg_mem;
+
+ struct vbi_info vbi;
+
+ u32 pgm_info_offset;
+ u32 pgm_info_num;
+ u32 pgm_info_write_idx;
+ u32 pgm_info_read_idx;
+ struct v4l2_enc_idx_entry pgm_info[CX18_MAX_PGM_INDEX];
+
+ u64 mpg_data_received;
+ u64 vbi_data_inserted;
+
+ wait_queue_head_t mb_apu_waitq;
+ wait_queue_head_t mb_cpu_waitq;
+ wait_queue_head_t mb_epu_waitq;
+ wait_queue_head_t mb_hpu_waitq;
+ wait_queue_head_t cap_w;
+ /* when the current DMA is finished this queue is woken up */
+ wait_queue_head_t dma_waitq;
+
+ /* i2c */
+ struct i2c_adapter i2c_adap[2];
+ struct i2c_algo_bit_data i2c_algo[2];
+ struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2];
+ struct i2c_client i2c_client[2];
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex i2c_bus_lock[2];
+#else
+ struct semaphore i2c_bus_lock[2];
+#endif
+ struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
+
+ /* gpio */
+ u32 gpio_dir;
+ u32 gpio_val;
+
+ /* v4l2 and User settings */
+
+ /* codec settings */
+ u32 audio_input;
+ u32 active_input;
+ u32 active_output;
+ v4l2_std_id std;
+ v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
+};
+
+/* Globals */
+extern struct cx18 *cx18_cards[];
+extern int cx18_cards_active;
+extern int cx18_first_minor;
+extern spinlock_t cx18_cards_lock;
+
+/*==============Prototypes==================*/
+
+/* Return non-zero if a signal is pending */
+int cx18_msleep_timeout(unsigned int msecs, int intr);
+
+/* Read Hauppauge eeprom */
+struct tveeprom; /* forward reference */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
+
+/* First-open initialization: load firmware, etc. */
+int cx18_init_on_first_open(struct cx18 *cx);
+
+/* This is a PCI post thing, where if the pci register is not read, then
+ the write doesn't always take effect right away. By reading back the
+ register any pending PCI writes will be performed (in order), and so
+ you can be sure that the writes are guaranteed to be done.
+
+ Rarely needed, only in some timing sensitive cases.
+ Apparently if this is not done some motherboards seem
+ to kill the firmware and get into the broken state until computer is
+ rebooted. */
+#define write_sync(val, reg) \
+ do { writel(val, reg); readl(reg); } while (0)
+
+#define read_reg(reg) readl(cx->reg_mem + (reg))
+#define write_reg(val, reg) writel(val, cx->reg_mem + (reg))
+#define write_reg_sync(val, reg) \
+ do { write_reg(val, reg); read_reg(reg); } while (0)
+
+#define read_enc(addr) readl(cx->enc_mem + (u32)(addr))
+#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr))
+#define write_enc_sync(val, addr) \
+ do { write_enc(val, addr); read_enc(addr); } while (0)
+
+#define sw1_irq_enable(val) do { \
+ write_reg(val, SW1_INT_STATUS); \
+ write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \
+} while (0)
+
+#define sw1_irq_disable(val) \
+ write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI);
+
+#define sw2_irq_enable(val) do { \
+ write_reg(val, SW2_INT_STATUS); \
+ write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \
+} while (0)
+
+#define sw2_irq_disable(val) \
+ write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI);
+
+#define setup_page(addr) do { \
+ u32 val = read_reg(0xD000F8) & ~0x1f00; \
+ write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \
+} while (0)
+
+#endif /* CX18_DRIVER_H */
diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c
new file mode 100644
index 000000000..c9744173f
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-dvb.c
@@ -0,0 +1,286 @@
+/*
+ * cx18 functions for DVB support
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx18-version.h"
+#include "cx18-dvb.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "s5h1409.h"
+#include "mxl5005s.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
+
+static struct mxl5005s_config hauppauge_hvr1600_tuner = {
+ .i2c_address = 0xC6 >> 1,
+ .if_freq = IF_FREQ_5380000HZ,
+ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
+ .agc_mode = MXL_SINGLE_AGC,
+ .tracking_filter = MXL_TF_C_H,
+ .rssi_enable = MXL_RSSI_ENABLE,
+ .cap_select = MXL_CAP_SEL_ENABLE,
+ .div_out = MXL_DIV_OUT_4,
+ .clock_out = MXL_CLOCK_OUT_DISABLE,
+ .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+ .top = MXL5005S_TOP_25P2,
+ .mod_mode = MXL_DIGITAL_MODE,
+ .if_mode = MXL_ZERO_IF,
+ .AgcMasterByte = 0x00,
+};
+
+static struct s5h1409_config hauppauge_hvr1600_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+
+};
+
+static int dvb_register(struct cx18_stream *stream);
+
+/* Kernel DVB framework calls this when the feed needs to start.
+ * The CX18 framework should enable the transport DMA handling
+ * and queue processing.
+ */
+static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
+ struct cx18 *cx = stream->cx;
+ int ret = -EINVAL;
+ u32 v;
+
+ CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+ v |= 0x00400000; /* Serial Mode */
+ v |= 0x00002000; /* Data Length - Byte */
+ v |= 0x00010000; /* Error - Polarity */
+ v |= 0x00020000; /* Error - Passthru */
+ v |= 0x000c0000; /* Error - Ignore */
+ write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+ break;
+
+ default:
+ /* Assumption - Parallel transport - Signalling
+ * undefined or default.
+ */
+ break;
+ }
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ if (stream) {
+ mutex_lock(&stream->dvb.feedlock);
+ if (stream->dvb.feeding++ == 0) {
+ CX18_DEBUG_INFO("Starting Transport DMA\n");
+ ret = cx18_start_v4l2_encode_stream(stream);
+ } else
+ ret = 0;
+ mutex_unlock(&stream->dvb.feedlock);
+ }
+
+ return ret;
+}
+
+/* Kernel DVB framework calls this when the feed needs to stop. */
+static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
+ struct cx18 *cx = stream->cx;
+ int ret = -EINVAL;
+
+ CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+
+ if (stream) {
+ mutex_lock(&stream->dvb.feedlock);
+ if (--stream->dvb.feeding == 0) {
+ CX18_DEBUG_INFO("Stopping Transport DMA\n");
+ ret = cx18_stop_v4l2_encode_stream(stream, 0);
+ } else
+ ret = 0;
+ mutex_unlock(&stream->dvb.feedlock);
+ }
+
+ return ret;
+}
+
+int cx18_dvb_register(struct cx18_stream *stream)
+{
+ struct cx18 *cx = stream->cx;
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+ int ret;
+
+ if (!dvb)
+ return -EINVAL;
+
+ ret = dvb_register_adapter(&dvb->dvb_adapter,
+ CX18_DRIVER_NAME,
+ THIS_MODULE, &cx->dev->dev, adapter_nr);
+ if (ret < 0)
+ goto err_out;
+
+ dvb_adapter = &dvb->dvb_adapter;
+
+ dvbdemux = &dvb->demux;
+
+ dvbdemux->priv = (void *)stream;
+
+ dvbdemux->filternum = 256;
+ dvbdemux->feednum = 256;
+ dvbdemux->start_feed = cx18_dvb_start_feed;
+ dvbdemux->stop_feed = cx18_dvb_stop_feed;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+ ret = dvb_dmx_init(dvbdemux);
+ if (ret < 0)
+ goto err_dvb_unregister_adapter;
+
+ dmx = &dvbdemux->dmx;
+
+ dvb->hw_frontend.source = DMX_FRONTEND_0;
+ dvb->mem_frontend.source = DMX_MEMORY_FE;
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = dmx;
+
+ ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter);
+ if (ret < 0)
+ goto err_dvb_dmx_release;
+
+ ret = dmx->add_frontend(dmx, &dvb->hw_frontend);
+ if (ret < 0)
+ goto err_dvb_dmxdev_release;
+
+ ret = dmx->add_frontend(dmx, &dvb->mem_frontend);
+ if (ret < 0)
+ goto err_remove_hw_frontend;
+
+ ret = dmx->connect_frontend(dmx, &dvb->hw_frontend);
+ if (ret < 0)
+ goto err_remove_mem_frontend;
+
+ ret = dvb_register(stream);
+ if (ret < 0)
+ goto err_disconnect_frontend;
+
+ dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
+
+ CX18_INFO("DVB Frontend registered\n");
+ mutex_init(&dvb->feedlock);
+ dvb->enabled = 1;
+ return ret;
+
+err_disconnect_frontend:
+ dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+ dmx->remove_frontend(dmx, &dvb->mem_frontend);
+err_remove_hw_frontend:
+ dmx->remove_frontend(dmx, &dvb->hw_frontend);
+err_dvb_dmxdev_release:
+ dvb_dmxdev_release(&dvb->dmxdev);
+err_dvb_dmx_release:
+ dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+ dvb_unregister_adapter(dvb_adapter);
+err_out:
+ return ret;
+}
+
+void cx18_dvb_unregister(struct cx18_stream *stream)
+{
+ struct cx18 *cx = stream->cx;
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+
+ CX18_INFO("unregister DVB\n");
+
+ dvb_adapter = &dvb->dvb_adapter;
+ dvbdemux = &dvb->demux;
+ dmx = &dvbdemux->dmx;
+
+ dmx->close(dmx);
+ dvb_net_release(&dvb->dvbnet);
+ dmx->remove_frontend(dmx, &dvb->mem_frontend);
+ dmx->remove_frontend(dmx, &dvb->hw_frontend);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(dvbdemux);
+ dvb_unregister_frontend(dvb->fe);
+ dvb_frontend_detach(dvb->fe);
+ dvb_unregister_adapter(dvb_adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+static int dvb_register(struct cx18_stream *stream)
+{
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18 *cx = stream->cx;
+ int ret = 0;
+
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ dvb->fe = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1600_config,
+ &cx->i2c_adap[0]);
+ if (dvb->fe != NULL) {
+ dvb_attach(mxl5005s_attach, dvb->fe,
+ &cx->i2c_adap[0],
+ &hauppauge_hvr1600_tuner);
+ ret = 0;
+ }
+ break;
+ default:
+ /* No Digital Tv Support */
+ break;
+ }
+
+ if (dvb->fe == NULL) {
+ CX18_ERR("frontend initialization failed\n");
+ return -1;
+ }
+
+ ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
+ if (ret < 0) {
+ if (dvb->fe->ops.release)
+ dvb->fe->ops.release(dvb->fe);
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-dvb.h b/linux/drivers/media/video/cx18/cx18-dvb.h
new file mode 100644
index 000000000..d6a6ccda7
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-dvb.h
@@ -0,0 +1,25 @@
+/*
+ * cx18 functions for DVB support
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cx18-driver.h"
+
+int cx18_dvb_register(struct cx18_stream *stream);
+void cx18_dvb_unregister(struct cx18_stream *stream);
diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c
new file mode 100644
index 000000000..12f9de74d
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-fileops.c
@@ -0,0 +1,749 @@
+/*
+ * cx18 file operation functions
+ *
+ * Derived from ivtv-fileops.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-fileops.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-vbi.h"
+#include "cx18-audio.h"
+#include "cx18-mailbox.h"
+#include "cx18-scb.h"
+#include "cx18-streams.h"
+#include "cx18-controls.h"
+#include "cx18-ioctl.h"
+#include "cx18-cards.h"
+
+/* This function tries to claim the stream for a specific file descriptor.
+ If no one else is using this stream then the stream is claimed and
+ associated VBI streams are also automatically claimed.
+ Possible error returns: -EBUSY if someone else has claimed
+ the stream or 0 on success. */
+static int cx18_claim_stream(struct cx18_open_id *id, int type)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[type];
+ struct cx18_stream *s_vbi;
+ int vbi_type;
+
+ if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
+ /* someone already claimed this stream */
+ if (s->id == id->open_id) {
+ /* yes, this file descriptor did. So that's OK. */
+ return 0;
+ }
+ if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) {
+ /* VBI is handled already internally, now also assign
+ the file descriptor to this stream for external
+ reading of the stream. */
+ s->id = id->open_id;
+ CX18_DEBUG_INFO("Start Read VBI\n");
+ return 0;
+ }
+ /* someone else is using this stream already */
+ CX18_DEBUG_INFO("Stream %d is busy\n", type);
+ return -EBUSY;
+ }
+ s->id = id->open_id;
+
+ /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
+ CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
+ (provided VBI insertion is on and sliced VBI is selected), for all
+ other streams we're done */
+ if (type == CX18_ENC_STREAM_TYPE_MPG &&
+ cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
+ vbi_type = CX18_ENC_STREAM_TYPE_VBI;
+ } else {
+ return 0;
+ }
+ s_vbi = &cx->streams[vbi_type];
+
+ set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
+
+ /* mark that it is used internally */
+ set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags);
+ return 0;
+}
+
+/* This function releases a previously claimed stream. It will take into
+ account associated VBI streams. */
+static void cx18_release_stream(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_stream *s_vbi;
+
+ s->id = -1;
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) {
+ /* this stream is still in use internally */
+ return;
+ }
+ if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
+ CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name);
+ return;
+ }
+
+ cx18_flush_queues(s);
+
+ /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI,
+ for all other streams we're done */
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ else
+ return;
+
+ /* clear internal use flag */
+ if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
+ /* was already cleared */
+ return;
+ }
+ if (s_vbi->id != -1) {
+ /* VBI stream still claimed by a file descriptor */
+ return;
+ }
+ clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
+ cx18_flush_queues(s_vbi);
+}
+
+static void cx18_dualwatch(struct cx18 *cx)
+{
+ struct v4l2_tuner vt;
+ u16 new_bitmap;
+ u16 new_stereo_mode;
+ const u16 stereo_mask = 0x0300;
+ const u16 dual = 0x0200;
+
+ new_stereo_mode = cx->params.audio_properties & stereo_mask;
+ memset(&vt, 0, sizeof(vt));
+ cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt);
+ if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
+ (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
+ new_stereo_mode = dual;
+
+ if (new_stereo_mode == cx->dualwatch_stereo_mode)
+ return;
+
+ new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask);
+
+ CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
+ cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
+
+ if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
+ cx18_find_handle(cx), new_bitmap) == 0) {
+ cx->dualwatch_stereo_mode = new_stereo_mode;
+ return;
+ }
+ CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+}
+
+#if 0
+static void cx18_update_pgm_info(struct cx18 *cx)
+{
+ u32 wr_idx = (read_enc(cx->pgm_info_offset) - cx->pgm_info_offset - 4) / 24;
+ int cnt;
+ int i = 0;
+
+ if (wr_idx >= cx->pgm_info_num) {
+ CX18_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, cx->pgm_info_num);
+ return;
+ }
+ cnt = (wr_idx + cx->pgm_info_num - cx->pgm_info_write_idx) % cx->pgm_info_num;
+ while (i < cnt) {
+ int idx = (cx->pgm_info_write_idx + i) % cx->pgm_info_num;
+ struct v4l2_enc_idx_entry *e = cx->pgm_info + idx;
+ u32 addr = cx->pgm_info_offset + 4 + idx * 24;
+ const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 };
+
+ e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
+ if (e->offset > cx->mpg_data_received)
+ break;
+ e->offset += cx->vbi_data_inserted;
+ e->length = read_enc(addr);
+ e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
+ e->flags = mapping[read_enc(addr + 12) & 3];
+ i++;
+ }
+ cx->pgm_info_write_idx = (cx->pgm_info_write_idx + i) % cx->pgm_info_num;
+}
+#endif
+
+static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ struct cx18_buffer *buf;
+ DEFINE_WAIT(wait);
+
+ *err = 0;
+ while (1) {
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+#if 0
+ /* Process pending program info updates and pending
+ VBI data */
+ cx18_update_pgm_info(cx);
+#endif
+
+ if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
+ cx->dualwatch_jiffies = jiffies;
+ cx18_dualwatch(cx);
+ }
+ if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+ while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
+ /* byteswap and process VBI data */
+/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */
+ cx18_enqueue(s_vbi, buf, &s_vbi->q_free);
+ }
+ }
+ buf = &cx->vbi.sliced_mpeg_buf;
+ if (buf->readpos != buf->bytesused)
+ return buf;
+ }
+
+ /* do we have leftover data? */
+ buf = cx18_dequeue(s, &s->q_io);
+ if (buf)
+ return buf;
+
+ /* do we have new data? */
+ buf = cx18_dequeue(s, &s->q_full);
+ if (buf) {
+ if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP,
+ &buf->b_flags))
+ return buf;
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ /* byteswap MPG data */
+ cx18_buf_swap(buf);
+ else {
+ /* byteswap and process VBI data */
+ cx18_process_vbi_data(cx, buf,
+ s->dma_pts, s->type);
+ }
+ return buf;
+ }
+
+ /* return if end of stream */
+ if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ CX18_DEBUG_INFO("EOS %s\n", s->name);
+ return NULL;
+ }
+
+ /* return if file was opened with O_NONBLOCK */
+ if (non_block) {
+ *err = -EAGAIN;
+ return NULL;
+ }
+
+ /* wait for more data to arrive */
+ prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+ /* New buffers might have become available before we were added
+ to the waitqueue */
+ if (!s->q_full.buffers)
+ schedule();
+ finish_wait(&s->waitq, &wait);
+ if (signal_pending(current)) {
+ /* return if a signal was received */
+ CX18_DEBUG_INFO("User stopped %s\n", s->name);
+ *err = -EINTR;
+ return NULL;
+ }
+ }
+}
+
+static void cx18_setup_sliced_vbi_buf(struct cx18 *cx)
+{
+ int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
+
+ cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx];
+ cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx];
+ cx->vbi.sliced_mpeg_buf.readpos = 0;
+}
+
+static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
+ struct cx18_buffer *buf, char __user *ubuf, size_t ucount)
+{
+ struct cx18 *cx = s->cx;
+ size_t len = buf->bytesused - buf->readpos;
+
+ if (len > ucount)
+ len = ucount;
+ if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) {
+ const char *start = buf->buf + buf->readpos;
+ const char *p = start + 1;
+ const u8 *q;
+ u8 ch = cx->search_pack_header ? 0xba : 0xe0;
+ int stuffing, i;
+
+ while (start + len > p) {
+ q = memchr(p, 0, start + len - p);
+ if (q == NULL)
+ break;
+ p = q + 1;
+ if ((char *)q + 15 >= buf->buf + buf->bytesused ||
+ q[1] != 0 || q[2] != 1 || q[3] != ch)
+ continue;
+ if (!cx->search_pack_header) {
+ if ((q[6] & 0xc0) != 0x80)
+ continue;
+ if (((q[7] & 0xc0) == 0x80 &&
+ (q[9] & 0xf0) == 0x20) ||
+ ((q[7] & 0xc0) == 0xc0 &&
+ (q[9] & 0xf0) == 0x30)) {
+ ch = 0xba;
+ cx->search_pack_header = 1;
+ p = q + 9;
+ }
+ continue;
+ }
+ stuffing = q[13] & 7;
+ /* all stuffing bytes must be 0xff */
+ for (i = 0; i < stuffing; i++)
+ if (q[14 + i] != 0xff)
+ break;
+ if (i == stuffing &&
+ (q[4] & 0xc4) == 0x44 &&
+ (q[12] & 3) == 3 &&
+ q[14 + stuffing] == 0 &&
+ q[15 + stuffing] == 0 &&
+ q[16 + stuffing] == 1) {
+ cx->search_pack_header = 0;
+ len = (char *)q - start;
+ cx18_setup_sliced_vbi_buf(cx);
+ break;
+ }
+ }
+ }
+ if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
+ CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n",
+ len, s->name);
+ return -EFAULT;
+ }
+ buf->readpos += len;
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ buf != &cx->vbi.sliced_mpeg_buf)
+ cx->mpg_data_received += len;
+ return len;
+}
+
+static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
+ size_t tot_count, int non_block)
+{
+ struct cx18 *cx = s->cx;
+ size_t tot_written = 0;
+ int single_frame = 0;
+
+ if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) {
+ /* shouldn't happen */
+ CX18_DEBUG_WARN("Stream %s not initialized before read\n",
+ s->name);
+ return -EIO;
+ }
+
+ /* Each VBI buffer is one frame, the v4l2 API says that for VBI the
+ frames should arrive one-by-one, so make sure we never output more
+ than one VBI frame at a time */
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
+ cx->vbi.sliced_in->service_set)
+ single_frame = 1;
+
+ for (;;) {
+ struct cx18_buffer *buf;
+ int rc;
+
+ buf = cx18_get_buffer(s, non_block, &rc);
+ /* if there is no data available... */
+ if (buf == NULL) {
+ /* if we got data, then return that regardless */
+ if (tot_written)
+ break;
+ /* EOS condition */
+ if (rc == 0) {
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+ clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ cx18_release_stream(s);
+ }
+ /* set errno */
+ return rc;
+ }
+
+ rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written,
+ tot_count - tot_written);
+
+ if (buf != &cx->vbi.sliced_mpeg_buf) {
+ if (buf->readpos == buf->bytesused) {
+ cx18_buf_sync_for_device(s, buf);
+ cx18_enqueue(s, buf, &s->q_free);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
+ s->handle,
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] -
+ cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ } else
+ cx18_enqueue(s, buf, &s->q_io);
+ } else if (buf->readpos == buf->bytesused) {
+ int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
+
+ cx->vbi.sliced_mpeg_size[idx] = 0;
+ cx->vbi.inserted_frame++;
+ cx->vbi_data_inserted += buf->bytesused;
+ }
+ if (rc < 0)
+ return rc;
+ tot_written += rc;
+
+ if (tot_written == tot_count || single_frame)
+ break;
+ }
+ return tot_written;
+}
+
+static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf,
+ size_t count, loff_t *pos, int non_block)
+{
+ ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0;
+ struct cx18 *cx = s->cx;
+
+ CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
+ if (rc > 0)
+ pos += rc;
+ return rc;
+}
+
+int cx18_start_capture(struct cx18_open_id *id)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ struct cx18_stream *s_vbi;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* you cannot read from these stream types. */
+ return -EPERM;
+ }
+
+ /* Try to claim this stream. */
+ if (cx18_claim_stream(id, s->type))
+ return -EBUSY;
+
+ /* If capture is already in progress, then we also have to
+ do nothing extra. */
+ if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||
+ test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ set_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ return 0;
+ }
+
+ /* Start VBI capture if required */
+ s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
+ /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed
+ automatically when the MPG stream is claimed.
+ We only need to start the VBI capturing. */
+ if (cx18_start_v4l2_encode_stream(s_vbi)) {
+ CX18_DEBUG_WARN("VBI capture start failed\n");
+
+ /* Failure, clean up and return an error */
+ clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+ /* also releases the associated VBI stream */
+ cx18_release_stream(s);
+ return -EIO;
+ }
+ CX18_DEBUG_INFO("VBI insertion started\n");
+ }
+
+ /* Tell the card to start capturing */
+ if (!cx18_start_v4l2_encode_stream(s)) {
+ /* We're done */
+ set_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ /* Resume a possibly paused encoder */
+ if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle);
+ return 0;
+ }
+
+ /* failure, clean up */
+ CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
+
+ /* Note: the CX18_ENC_STREAM_TYPE_VBI is released
+ automatically when the MPG stream is released.
+ We only need to stop the VBI capturing. */
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
+ cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ }
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+ cx18_release_stream(s);
+ return -EIO;
+}
+
+ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ int rc;
+
+ CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
+
+ mutex_lock(&cx->serialize_lock);
+ rc = cx18_start_capture(id);
+ mutex_unlock(&cx->serialize_lock);
+ if (rc)
+ return rc;
+ return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+}
+
+unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+ /* Start a capture if there is none */
+ if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ int rc;
+
+ mutex_lock(&cx->serialize_lock);
+ rc = cx18_start_capture(id);
+ mutex_unlock(&cx->serialize_lock);
+ if (rc) {
+ CX18_DEBUG_INFO("Could not start capture for %s (%d)\n",
+ s->name, rc);
+ return POLLERR;
+ }
+ CX18_DEBUG_FILE("Encoder poll started capture\n");
+ }
+
+ /* add stream's waitq to the poll list */
+ CX18_DEBUG_HI_FILE("Encoder poll\n");
+ poll_wait(filp, &s->waitq, wait);
+
+ if (s->q_full.length || s->q_io.length)
+ return POLLIN | POLLRDNORM;
+ if (eof)
+ return POLLHUP;
+ return 0;
+}
+
+void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ CX18_DEBUG_IOCTL("close() of %s\n", s->name);
+
+ /* 'Unclaim' this stream */
+
+ /* Stop capturing */
+ if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ struct cx18_stream *s_vbi =
+ &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+
+ CX18_DEBUG_INFO("close stopping capture\n");
+ /* Special case: a running VBI capture for VBI insertion
+ in the mpeg stream. Need to stop that too. */
+ if (id->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
+ !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+ CX18_DEBUG_INFO("close stopping embedded VBI capture\n");
+ cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ }
+ if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
+ /* Also used internally, don't stop capturing */
+ s->id = -1;
+ else
+ cx18_stop_v4l2_encode_stream(s, gop_end);
+ }
+ if (!gop_end) {
+ clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+ cx18_release_stream(s);
+ }
+}
+
+int cx18_v4l2_close(struct inode *inode, struct file *filp)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ CX18_DEBUG_IOCTL("close() of %s\n", s->name);
+
+ v4l2_prio_close(&cx->prio, &id->prio);
+
+ /* Easy case first: this stream was never claimed by us */
+ if (s->id != id->open_id) {
+ kfree(id);
+ return 0;
+ }
+
+ /* 'Unclaim' this stream */
+
+ /* Stop radio */
+ mutex_lock(&cx->serialize_lock);
+ if (id->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* Closing radio device, return to TV mode */
+ cx18_mute(cx);
+ /* Mark that the radio is no longer in use */
+ clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+ /* Switch tuner to TV */
+ cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ /* Select correct audio input (i.e. TV tuner or Line in) */
+ cx18_audio_set_io(cx);
+ if (atomic_read(&cx->ana_capturing) > 0) {
+ /* Undo video mute */
+ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
+ cx->params.video_mute |
+ (cx->params.video_mute_yuv << 8));
+ }
+ /* Done! Unmute and continue. */
+ cx18_unmute(cx);
+ cx18_release_stream(s);
+ } else {
+ cx18_stop_capture(id, 0);
+ }
+ kfree(id);
+ mutex_unlock(&cx->serialize_lock);
+ return 0;
+}
+
+static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_open_id *item;
+
+ CX18_DEBUG_FILE("open %s\n", s->name);
+
+ /* Allocate memory */
+ item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL);
+ if (NULL == item) {
+ CX18_DEBUG_WARN("nomem on v4l2 open\n");
+ return -ENOMEM;
+ }
+ item->cx = cx;
+ item->type = s->type;
+ v4l2_prio_open(&cx->prio, &item->prio);
+
+ item->open_id = cx->open_id++;
+ filp->private_data = item;
+
+ if (item->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* Try to claim this stream */
+ if (cx18_claim_stream(item, item->type)) {
+ /* No, it's already in use */
+ kfree(item);
+ return -EBUSY;
+ }
+
+ if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ if (atomic_read(&cx->ana_capturing) > 0) {
+ /* switching to radio while capture is
+ in progress is not polite */
+ cx18_release_stream(s);
+ kfree(item);
+ return -EBUSY;
+ }
+ }
+
+ /* Mark that the radio is being used. */
+ set_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+ /* We have the radio */
+ cx18_mute(cx);
+ /* Switch tuner to radio */
+ cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL);
+ /* Select the correct audio input (i.e. radio tuner) */
+ cx18_audio_set_io(cx);
+ /* Done! Unmute and continue. */
+ cx18_unmute(cx);
+ }
+ return 0;
+}
+
+int cx18_v4l2_open(struct inode *inode, struct file *filp)
+{
+ int res, x, y = 0;
+ struct cx18 *cx = NULL;
+ struct cx18_stream *s = NULL;
+ int minor = iminor(inode);
+
+ /* Find which card this open was on */
+ spin_lock(&cx18_cards_lock);
+ for (x = 0; cx == NULL && x < cx18_cards_active; x++) {
+ /* find out which stream this open was on */
+ for (y = 0; y < CX18_MAX_STREAMS; y++) {
+ if (cx18_cards[x] == NULL)
+ continue;
+ s = &cx18_cards[x]->streams[y];
+ if (s->v4l2dev && s->v4l2dev->minor == minor) {
+ cx = cx18_cards[x];
+ break;
+ }
+ }
+ }
+ spin_unlock(&cx18_cards_lock);
+
+ if (cx == NULL) {
+ /* Couldn't find a device registered
+ on that minor, shouldn't happen! */
+ printk(KERN_WARNING "No cx18 device found on minor %d\n",
+ minor);
+ return -ENXIO;
+ }
+
+ mutex_lock(&cx->serialize_lock);
+ if (cx18_init_on_first_open(cx)) {
+ CX18_ERR("Failed to initialize on minor %d\n", minor);
+ mutex_unlock(&cx->serialize_lock);
+ return -ENXIO;
+ }
+ res = cx18_serialized_open(s, filp);
+ mutex_unlock(&cx->serialize_lock);
+ return res;
+}
+
+void cx18_mute(struct cx18 *cx)
+{
+ if (atomic_read(&cx->ana_capturing))
+ cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ cx18_find_handle(cx), 1);
+ CX18_DEBUG_INFO("Mute\n");
+}
+
+void cx18_unmute(struct cx18 *cx)
+{
+ if (atomic_read(&cx->ana_capturing)) {
+ cx18_msleep_timeout(100, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
+ cx18_find_handle(cx), 12);
+ cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ cx18_find_handle(cx), 0);
+ }
+ CX18_DEBUG_INFO("Unmute\n");
+}
diff --git a/linux/drivers/media/video/cx18/cx18-fileops.h b/linux/drivers/media/video/cx18/cx18-fileops.h
new file mode 100644
index 000000000..46da0282f
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-fileops.h
@@ -0,0 +1,36 @@
+/*
+ * cx18 file operation functions
+ *
+ * Derived from ivtv-fileops.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+/* Testing/Debugging */
+int cx18_v4l2_open(struct inode *inode, struct file *filp);
+ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos);
+ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *pos);
+int cx18_v4l2_close(struct inode *inode, struct file *filp);
+unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait);
+int cx18_start_capture(struct cx18_open_id *id);
+void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
+void cx18_mute(struct cx18 *cx);
+void cx18_unmute(struct cx18 *cx);
+
diff --git a/linux/drivers/media/video/cx18/cx18-firmware.c b/linux/drivers/media/video/cx18/cx18-firmware.c
new file mode 100644
index 000000000..5e37427ec
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-firmware.c
@@ -0,0 +1,380 @@
+/*
+ * cx18 firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-firmware.h"
+#include "cx18-cards.h"
+#include <linux/firmware.h>
+
+#define CX18_PROC_SOFT_RESET 0xc70010
+#define CX18_DDR_SOFT_RESET 0xc70014
+#define CX18_CLOCK_SELECT1 0xc71000
+#define CX18_CLOCK_SELECT2 0xc71004
+#define CX18_HALF_CLOCK_SELECT1 0xc71008
+#define CX18_HALF_CLOCK_SELECT2 0xc7100C
+#define CX18_CLOCK_POLARITY1 0xc71010
+#define CX18_CLOCK_POLARITY2 0xc71014
+#define CX18_ADD_DELAY_ENABLE1 0xc71018
+#define CX18_ADD_DELAY_ENABLE2 0xc7101C
+#define CX18_CLOCK_ENABLE1 0xc71020
+#define CX18_CLOCK_ENABLE2 0xc71024
+
+#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
+
+#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
+
+#define CX18_FAST_CLOCK_PLL_INT 0xc78000
+#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
+#define CX18_FAST_CLOCK_PLL_POST 0xc78008
+#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C
+#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010
+
+#define CX18_SLOW_CLOCK_PLL_INT 0xc78014
+#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018
+#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C
+#define CX18_MPEG_CLOCK_PLL_INT 0xc78040
+#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044
+#define CX18_MPEG_CLOCK_PLL_POST 0xc78048
+#define CX18_PLL_POWER_DOWN 0xc78088
+#define CX18_SW1_INT_STATUS 0xc73104
+#define CX18_SW1_INT_ENABLE_PCI 0xc7311C
+#define CX18_SW2_INT_SET 0xc73140
+#define CX18_SW2_INT_STATUS 0xc73144
+#define CX18_ADEC_CONTROL 0xc78120
+
+#define CX18_DDR_REQUEST_ENABLE 0xc80000
+#define CX18_DDR_CHIP_CONFIG 0xc80004
+#define CX18_DDR_REFRESH 0xc80008
+#define CX18_DDR_TIMING1 0xc8000C
+#define CX18_DDR_TIMING2 0xc80010
+#define CX18_DDR_POWER_REG 0xc8001C
+
+#define CX18_DDR_TUNE_LANE 0xc80048
+#define CX18_DDR_INITIAL_EMRS 0xc80054
+#define CX18_DDR_MB_PER_ROW_7 0xc8009C
+#define CX18_DDR_BASE_63_ADDR 0xc804FC
+
+#define CX18_WMB_CLIENT02 0xc90108
+#define CX18_WMB_CLIENT05 0xc90114
+#define CX18_WMB_CLIENT06 0xc90118
+#define CX18_WMB_CLIENT07 0xc9011C
+#define CX18_WMB_CLIENT08 0xc90120
+#define CX18_WMB_CLIENT09 0xc90124
+#define CX18_WMB_CLIENT10 0xc90128
+#define CX18_WMB_CLIENT11 0xc9012C
+#define CX18_WMB_CLIENT12 0xc90130
+#define CX18_WMB_CLIENT13 0xc90134
+#define CX18_WMB_CLIENT14 0xc90138
+
+#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
+
+/* Encoder/decoder firmware sizes */
+#define CX18_FW_CPU_SIZE (174716)
+#define CX18_FW_APU_SIZE (141200)
+
+#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
+#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */
+
+struct cx18_apu_rom_seghdr {
+ u32 sync1;
+ u32 sync2;
+ u32 addr;
+ u32 size;
+};
+
+static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size)
+{
+ const struct firmware *fw = NULL;
+ int retries = 3;
+ int i, j;
+ u32 __iomem *dst = (u32 __iomem *)mem;
+ const u32 *src;
+
+retry:
+ if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) {
+ CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n",
+ fn, size);
+ CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+ }
+
+ src = (const u32 *)fw->data;
+
+ if (fw->size != size) {
+ /* Due to race conditions in firmware loading (esp. with
+ udev <0.95) the wrong file was sometimes loaded. So we check
+ filesizes to see if at least the right-sized file was
+ loaded. If not, then we retry. */
+ CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n",
+ fn, size, fw->size);
+ release_firmware(fw);
+ retries--;
+ goto retry;
+ }
+ for (i = 0; i < fw->size; i += 4096) {
+ setup_page(i);
+ for (j = i; j < fw->size && j < i + 4096; j += 4) {
+ /* no need for endianness conversion on the ppc */
+ __raw_writel(*src, dst);
+ if (__raw_readl(dst) != *src) {
+ CX18_ERR("Mismatch at offset %x\n", i);
+ release_firmware(fw);
+ return -EIO;
+ }
+ dst++;
+ src++;
+ }
+ }
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+ CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ release_firmware(fw);
+ return size;
+}
+
+static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size)
+{
+ const struct firmware *fw = NULL;
+ int retries = 3;
+ int i, j;
+ const u32 *src;
+ struct cx18_apu_rom_seghdr seghdr;
+ const u8 *vers;
+ u32 offset = 0;
+ u32 apu_version = 0;
+ int sz;
+
+retry:
+ if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) {
+ CX18_ERR("unable to open firmware %s (must be %ld bytes)\n",
+ fn, size);
+ CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+ }
+
+ src = (const u32 *)fw->data;
+ vers = fw->data + sizeof(seghdr);
+ sz = fw->size;
+
+ if (fw->size != size) {
+ /* Due to race conditions in firmware loading (esp. with
+ udev <0.95) the wrong file was sometimes loaded. So we check
+ filesizes to see if at least the right-sized file was
+ loaded. If not, then we retry. */
+ CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n",
+ fn, size, fw->size);
+ release_firmware(fw);
+ retries--;
+ goto retry;
+ }
+ apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
+ while (offset + sizeof(seghdr) < size) {
+ /* TODO: byteswapping */
+ memcpy(&seghdr, src + offset / 4, sizeof(seghdr));
+ offset += sizeof(seghdr);
+ if (seghdr.sync1 != APU_ROM_SYNC1 ||
+ seghdr.sync2 != APU_ROM_SYNC2) {
+ offset += seghdr.size;
+ continue;
+ }
+ CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
+ seghdr.addr + seghdr.size - 1);
+ if (offset + seghdr.size > sz)
+ break;
+ for (i = 0; i < seghdr.size; i += 4096) {
+ setup_page(offset + i);
+ for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
+ /* no need for endianness conversion on the ppc */
+ __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j);
+ if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) {
+ CX18_ERR("Mismatch at offset %x\n", offset + j);
+ release_firmware(fw);
+ return -EIO;
+ }
+ }
+ }
+ offset += seghdr.size;
+ }
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+ CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+ fn, apu_version, fw->size);
+ release_firmware(fw);
+ /* Clear bit0 for APU to start from 0 */
+ write_reg(read_reg(0xc72030) & ~1, 0xc72030);
+ return size;
+}
+
+void cx18_halt_firmware(struct cx18 *cx)
+{
+ CX18_DEBUG_INFO("Preparing for firmware halt.\n");
+ write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+ write_reg(0x00020002, CX18_ADEC_CONTROL);
+}
+
+void cx18_init_power(struct cx18 *cx, int lowpwr)
+{
+ /* power-down Spare and AOM PLLs */
+ /* power-up fast, slow and mpeg PLLs */
+ write_reg(0x00000008, CX18_PLL_POWER_DOWN);
+
+ /* ADEC out of sleep */
+ write_reg(0x00020000, CX18_ADEC_CONTROL);
+
+ /* The fast clock is at 200/245 MHz */
+ write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
+ write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC);
+
+ write_reg(2, CX18_FAST_CLOCK_PLL_POST);
+ write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE);
+ write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
+
+ /* set slow clock to 125/120 MHz */
+ write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
+ write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC);
+ write_reg(4, CX18_SLOW_CLOCK_PLL_POST);
+
+ /* mpeg clock pll 54MHz */
+ write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT);
+ write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
+ write_reg(8, CX18_MPEG_CLOCK_PLL_POST);
+
+ /* Defaults */
+ /* APU = SC or SC/2 = 125/62.5 */
+ /* EPU = SC = 125 */
+ /* DDR = FC = 180 */
+ /* ENC = SC = 125 */
+ /* AI1 = SC = 125 */
+ /* VIM2 = disabled */
+ /* PCI = FC/2 = 90 */
+ /* AI2 = disabled */
+ /* DEMUX = disabled */
+ /* AO = SC/2 = 62.5 */
+ /* SER = 54MHz */
+ /* VFC = disabled */
+ /* USB = disabled */
+
+ write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1);
+ write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2);
+
+ write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
+ write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
+
+ write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1);
+ write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2);
+}
+
+void cx18_init_memory(struct cx18 *cx)
+{
+ cx18_msleep_timeout(10, 0);
+ write_reg(0x10000, CX18_DDR_SOFT_RESET);
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
+
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH);
+ write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1);
+ write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2);
+
+ cx18_msleep_timeout(10, 0);
+
+ /* Initialize DQS pad time */
+ write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
+ write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
+
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(0x20000, CX18_DDR_SOFT_RESET);
+ cx18_msleep_timeout(10, 0);
+
+ /* use power-down mode when idle */
+ write_reg(0x00000010, CX18_DDR_POWER_REG);
+
+ write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN);
+
+ write_reg(0x48, CX18_DDR_MB_PER_ROW_7);
+ write_reg(0xE0000, CX18_DDR_BASE_63_ADDR);
+
+ write_reg(0x00000101, CX18_WMB_CLIENT02); /* AO */
+ write_reg(0x00000101, CX18_WMB_CLIENT09); /* AI2 */
+ write_reg(0x00000101, CX18_WMB_CLIENT05); /* VIM1 */
+ write_reg(0x00000101, CX18_WMB_CLIENT06); /* AI1 */
+ write_reg(0x00000101, CX18_WMB_CLIENT07); /* 3D comb */
+ write_reg(0x00000101, CX18_WMB_CLIENT10); /* ME */
+ write_reg(0x00000101, CX18_WMB_CLIENT12); /* ENC */
+ write_reg(0x00000101, CX18_WMB_CLIENT13); /* PK */
+ write_reg(0x00000101, CX18_WMB_CLIENT11); /* RC */
+ write_reg(0x00000101, CX18_WMB_CLIENT14); /* AVO */
+}
+
+int cx18_firmware_init(struct cx18 *cx)
+{
+ /* Allow chip to control CLKRUN */
+ write_reg(0x5, CX18_DSP0_INTERRUPT_MASK);
+
+ write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+
+ cx18_msleep_timeout(1, 0);
+
+ sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+ sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ /* Only if the processor is not running */
+ if (read_reg(CX18_PROC_SOFT_RESET) & 8) {
+ int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
+ cx->enc_mem, cx, CX18_FW_APU_SIZE);
+#if 0
+ /* this might be needed after all, check later */
+ write_enc(0xE51FF004, 0);
+ write_enc(0xa00000, 4); /* todo: not hardcoded */
+ write_reg(0x00010000, CX18_PROC_SOFT_RESET); /* Start APU */
+ cx18_msleep_timeout(500, 0);
+#endif
+
+ sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
+ cx->enc_mem, cx, CX18_FW_CPU_SIZE);
+
+ if (sz > 0) {
+ int retries = 0;
+
+ /* start the CPU */
+ write_reg(0x00080000, CX18_PROC_SOFT_RESET);
+ while (retries++ < 50) { /* Loop for max 500mS */
+ if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0)
+ break;
+ cx18_msleep_timeout(10, 0);
+ }
+ cx18_msleep_timeout(200, 0);
+ if (retries == 51) {
+ CX18_ERR("Could not start the CPU\n");
+ return -EIO;
+ }
+ }
+ if (sz <= 0)
+ return -EIO;
+ }
+ /* initialize GPIO */
+ write_reg(0x14001400, 0xC78110);
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-firmware.h b/linux/drivers/media/video/cx18/cx18-firmware.h
new file mode 100644
index 000000000..38d4c05e8
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-firmware.h
@@ -0,0 +1,25 @@
+/*
+ * cx18 firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_firmware_init(struct cx18 *cx);
+void cx18_halt_firmware(struct cx18 *cx);
+void cx18_init_memory(struct cx18 *cx);
+void cx18_init_power(struct cx18 *cx, int lowpwr);
diff --git a/linux/drivers/media/video/cx18/cx18-gpio.c b/linux/drivers/media/video/cx18/cx18-gpio.c
new file mode 100644
index 000000000..ceb63653c
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-gpio.c
@@ -0,0 +1,100 @@
+/*
+ * cx18 gpio functions
+ *
+ * Derived from ivtv-gpio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "tuner-xc2028.h"
+
+/********************* GPIO stuffs *********************/
+
+/* GPIO registers */
+#define CX18_REG_GPIO_IN 0xc72010
+#define CX18_REG_GPIO_OUT1 0xc78100
+#define CX18_REG_GPIO_DIR1 0xc78108
+#define CX18_REG_GPIO_OUT2 0xc78104
+#define CX18_REG_GPIO_DIR2 0xc7810c
+
+/*
+ * HVR-1600 GPIO pins, courtesy of Hauppauge:
+ *
+ * gpio0: zilog ir process reset pin
+ * gpio1: zilog programming pin (you should never use this)
+ * gpio12: cx24227 reset pin
+ * gpio13: cs5345 reset pin
+*/
+
+static void gpio_write(struct cx18 *cx)
+{
+ u32 dir = cx->gpio_dir;
+ u32 val = cx->gpio_val;
+
+ write_reg((dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
+ write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
+ CX18_REG_GPIO_OUT1);
+ write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
+ write_reg((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
+ CX18_REG_GPIO_OUT2);
+}
+
+void cx18_gpio_init(struct cx18 *cx)
+{
+ cx->gpio_dir = cx->card->gpio_init.direction;
+ cx->gpio_val = cx->card->gpio_init.initial_value;
+
+ if (cx->card->tuners[0].tuner == TUNER_XC2028) {
+ cx->gpio_dir |= 1 << cx->card->xceive_pin;
+ cx->gpio_val |= 1 << cx->card->xceive_pin;
+ }
+
+ if (cx->gpio_dir == 0)
+ return;
+
+ CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
+ read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
+ read_reg(CX18_REG_GPIO_OUT1), read_reg(CX18_REG_GPIO_OUT2));
+
+ gpio_write(cx);
+}
+
+/* Xceive tuner reset function */
+int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
+{
+ struct i2c_algo_bit_data *algo = dev;
+ struct cx18_i2c_algo_callback_data *cb_data = algo->data;
+ struct cx18 *cx = cb_data->cx;
+
+ if (cmd != XC2028_TUNER_RESET)
+ return 0;
+ CX18_DEBUG_INFO("Resetting tuner\n");
+
+ cx->gpio_val &= ~(1 << cx->card->xceive_pin);
+
+ gpio_write(cx);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
+
+ cx->gpio_val |= 1 << cx->card->xceive_pin;
+ gpio_write(cx);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-gpio.h b/linux/drivers/media/video/cx18/cx18-gpio.h
new file mode 100644
index 000000000..41bac8856
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-gpio.h
@@ -0,0 +1,24 @@
+/*
+ * cx18 gpio functions
+ *
+ * Derived from ivtv-gpio.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+void cx18_gpio_init(struct cx18 *cx);
+int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c
new file mode 100644
index 000000000..30ec26a61
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-i2c.c
@@ -0,0 +1,465 @@
+/*
+ * cx18 I2C functions
+ *
+ * Derived from ivtv-i2c.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "cx18-av-core.h"
+#include "cx18-i2c.h"
+
+#include <media/ir-kbd-i2c.h>
+
+#define CX18_REG_I2C_1_WR 0xf15000
+#define CX18_REG_I2C_1_RD 0xf15008
+#define CX18_REG_I2C_2_WR 0xf25100
+#define CX18_REG_I2C_2_RD 0xf25108
+
+#define SETSCL_BIT 0x0001
+#define SETSDL_BIT 0x0002
+#define GETSCL_BIT 0x0004
+#define GETSDL_BIT 0x0008
+
+#ifndef I2C_ADAP_CLASS_TV_ANALOG
+#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
+#endif
+
+#define CX18_CS5345_I2C_ADDR 0x4c
+
+/* This array should match the CX18_HW_ defines */
+static const u8 hw_driverids[] = {
+ I2C_DRIVERID_TUNER,
+ I2C_DRIVERID_TVEEPROM,
+ I2C_DRIVERID_CS5345,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0 /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+static const u8 hw_addrs[] = {
+ 0,
+ 0,
+ CX18_CS5345_I2C_ADDR,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0, /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+/* This might well become a card-specific array */
+static const u8 hw_bus[] = {
+ 0,
+ 0,
+ 0,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0, /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+static const char * const hw_devicenames[] = {
+ "tuner",
+ "tveeprom",
+ "cs5345",
+ "gpio",
+ "cx23418",
+};
+
+int cx18_i2c_register(struct cx18 *cx, unsigned idx)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ struct i2c_board_info info;
+ struct i2c_client *c;
+ u8 id, bus;
+ int i;
+
+ CX18_DEBUG_I2C("i2c client register\n");
+ if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+ return -1;
+ id = hw_driverids[idx];
+ bus = hw_bus[idx];
+ memset(&info, 0, sizeof(info));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ strlcpy(info.driver_name, hw_devicenames[idx],
+ sizeof(info.driver_name));
+#else
+ strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
+#endif
+ info.addr = hw_addrs[idx];
+ for (i = 0; i < I2C_CLIENTS_MAX; i++)
+ if (cx->i2c_clients[i] == NULL)
+ break;
+
+ if (i == I2C_CLIENTS_MAX) {
+ CX18_ERR("insufficient room for new I2C client!\n");
+ return -ENOMEM;
+ }
+
+ if (id != I2C_DRIVERID_TUNER) {
+ c = i2c_new_device(&cx->i2c_adap[bus], &info);
+ if (c->driver == NULL)
+ i2c_unregister_device(c);
+ else
+ cx->i2c_clients[i] = c;
+ return cx->i2c_clients[i] ? 0 : -ENODEV;
+ }
+
+ /* special tuner handling */
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ return 0;
+#else
+ return 0;
+#endif
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+ struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter);
+ int i;
+
+ CX18_DEBUG_I2C("i2c client attach\n");
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ if (cx->i2c_clients[i] == NULL) {
+ cx->i2c_clients[i] = client;
+ break;
+ }
+ }
+ if (i == I2C_CLIENTS_MAX)
+ CX18_ERR("Insufficient room for new I2C client\n");
+#endif
+ return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+ int i;
+ struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter);
+
+ CX18_DEBUG_I2C("i2c client detach\n");
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ if (cx->i2c_clients[i] == client) {
+ cx->i2c_clients[i] = NULL;
+ break;
+ }
+ }
+ CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n",
+ client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
+
+ return 0;
+}
+
+static void cx18_setscl(void *data, int state)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
+ u32 r = read_reg(addr);
+
+ if (state)
+ write_reg_sync(r | SETSCL_BIT, addr);
+ else
+ write_reg_sync(r & ~SETSCL_BIT, addr);
+}
+
+static void cx18_setsda(void *data, int state)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
+ u32 r = read_reg(addr);
+
+ if (state)
+ write_reg_sync(r | SETSDL_BIT, addr);
+ else
+ write_reg_sync(r & ~SETSDL_BIT, addr);
+}
+
+static int cx18_getscl(void *data)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
+
+ return read_reg(addr) & GETSCL_BIT;
+}
+
+static int cx18_getsda(void *data)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
+
+ return read_reg(addr) & GETSDL_BIT;
+}
+
+/* template for i2c-bit-algo */
+static struct i2c_adapter cx18_i2c_adap_template = {
+ .name = "cx18 i2c driver",
+ .id = I2C_HW_B_CX2341X,
+ .algo = NULL, /* set by i2c-algo-bit */
+ .algo_data = NULL, /* filled from template */
+ .client_register = attach_inform,
+ .client_unregister = detach_inform,
+ .owner = THIS_MODULE,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+#ifdef I2C_ADAP_CLASS_TV_ANALOG
+ .class = I2C_ADAP_CLASS_TV_ANALOG,
+#endif
+#endif
+};
+
+#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */
+#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */
+
+static struct i2c_algo_bit_data cx18_i2c_algo_template = {
+ .setsda = cx18_setsda,
+ .setscl = cx18_setscl,
+ .getsda = cx18_getsda,
+ .getscl = cx18_getscl,
+ .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/
+ .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
+};
+
+static struct i2c_client cx18_i2c_client_template = {
+ .name = "cx18 internal",
+};
+
+int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg)
+{
+ struct i2c_client *client;
+ int retval;
+ int i;
+
+ CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ client = cx->i2c_clients[i];
+ if (client == NULL || client->driver == NULL ||
+ client->driver->command == NULL)
+ continue;
+ if (addr == client->addr) {
+ retval = client->driver->command(client, cmd, arg);
+ return retval;
+ }
+ }
+ if (cmd != VIDIOC_G_CHIP_IDENT)
+ CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n",
+ addr, cmd);
+ return -ENODEV;
+}
+
+/* Find the i2c device based on the driver ID and return
+ its i2c address or -ENODEV if no matching device was found. */
+static int cx18_i2c_id_addr(struct cx18 *cx, u32 id)
+{
+ struct i2c_client *client;
+ int retval = -ENODEV;
+ int i;
+
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ client = cx->i2c_clients[i];
+ if (client == NULL || client->driver == NULL)
+ continue;
+ if (id == client->driver->id) {
+ retval = client->addr;
+ break;
+ }
+ }
+ return retval;
+}
+
+/* Find the i2c device name matching the DRIVERID */
+static const char *cx18_i2c_id_name(u32 id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (hw_driverids[i] == id)
+ return hw_devicenames[i];
+ return "unknown device";
+}
+
+/* Find the i2c device name matching the CX18_HW_ flag */
+static const char *cx18_i2c_hw_name(u32 hw)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (1 << i == hw)
+ return hw_devicenames[i];
+ return "unknown device";
+}
+
+/* Find the i2c device matching the CX18_HW_ flag and return
+ its i2c address or -ENODEV if no matching device was found. */
+int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (1 << i == hw)
+ return cx18_i2c_id_addr(cx, hw_driverids[i]);
+ return -ENODEV;
+}
+
+/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing.
+ If hw == CX18_HW_GPIO then call the gpio handler. */
+int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
+{
+ int addr;
+
+ if (hw == CX18_HW_GPIO || hw == 0)
+ return 0;
+ if (hw == CX18_HW_CX23418)
+ return cx18_av_cmd(cx, cmd, arg);
+
+ addr = cx18_i2c_hw_addr(cx, hw);
+ if (addr < 0) {
+ CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n",
+ hw, cx18_i2c_hw_name(hw), cmd);
+ return addr;
+ }
+ return cx18_call_i2c_client(cx, addr, cmd, arg);
+}
+
+/* Calls i2c device based on I2C driver ID. */
+int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg)
+{
+ int addr;
+
+ addr = cx18_i2c_id_addr(cx, id);
+ if (addr < 0) {
+ if (cmd != VIDIOC_G_CHIP_IDENT)
+ CX18_ERR("i2c ID 0x%08x (%s) not found for cmd 0x%x!\n",
+ id, cx18_i2c_id_name(id), cmd);
+ return addr;
+ }
+ return cx18_call_i2c_client(cx, addr, cmd, arg);
+}
+
+/* broadcast cmd for all I2C clients and for the gpio subsystem */
+void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) {
+ CX18_ERR("adapter is not set\n");
+ return;
+ }
+ cx18_av_cmd(cx, cmd, arg);
+ i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
+ i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+}
+
+/* init + register i2c algo-bit adapter */
+int init_cx18_i2c(struct cx18 *cx)
+{
+ int i;
+ CX18_DEBUG_I2C("i2c init\n");
+
+ for (i = 0; i < 2; i++) {
+ memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
+ sizeof(struct i2c_adapter));
+ memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
+ sizeof(struct i2c_algo_bit_data));
+ cx->i2c_algo_cb_data[i].cx = cx;
+ cx->i2c_algo_cb_data[i].bus_index = i;
+ cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
+ cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
+
+ sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
+ " #%d-%d", cx->num, i);
+ i2c_set_adapdata(&cx->i2c_adap[i], cx);
+
+ memcpy(&cx->i2c_client[i], &cx18_i2c_client_template,
+ sizeof(struct i2c_client));
+ sprintf(cx->i2c_client[i].name +
+ strlen(cx->i2c_client[i].name), "%d", i);
+ cx->i2c_client[i].adapter = &cx->i2c_adap[i];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+ cx->i2c_adap[i].dev.parent = &cx->dev->dev;
+#endif
+ }
+
+ if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) {
+ /* Reset/Unreset I2C hardware block */
+ write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */
+ write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */
+ }
+ /* courtesy of Steven Toth <stoth@hauppauge.com> */
+ write_reg_sync(0x00c00000, 0xc7001c);
+ mdelay(10);
+ write_reg_sync(0x00c000c0, 0xc7001c);
+ mdelay(10);
+ write_reg_sync(0x00c00000, 0xc7001c);
+
+ write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
+ write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
+
+ /* Hw I2C1 Clock Freq ~100kHz */
+ write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR);
+ cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
+ cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
+
+ /* Hw I2C2 Clock Freq ~100kHz */
+ write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR);
+ cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
+ cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
+
+ return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
+ i2c_bit_add_bus(&cx->i2c_adap[1]);
+}
+
+void exit_cx18_i2c(struct cx18 *cx)
+{
+ int i;
+ CX18_DEBUG_I2C("i2c exit\n");
+ write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR);
+ write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR);
+
+ for (i = 0; i < 2; i++) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+ i2c_del_adapter(&cx->i2c_adap[i]);
+#else
+ i2c_bit_del_bus(&cx->i2c_adap[i]);
+#endif
+ }
+}
+
+/*
+ Hauppauge HVR1600 should have:
+ 32 cx24227
+ 98 unknown
+ a0 eeprom
+ c2 tuner
+ e? zilog ir
+ */
diff --git a/linux/drivers/media/video/cx18/cx18-i2c.h b/linux/drivers/media/video/cx18/cx18-i2c.h
new file mode 100644
index 000000000..113c3f9a2
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-i2c.h
@@ -0,0 +1,33 @@
+/*
+ * cx18 I2C functions
+ *
+ * Derived from ivtv-i2c.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw);
+int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg);
+int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg);
+int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg);
+void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_i2c_register(struct cx18 *cx, unsigned idx);
+
+/* init + register i2c algo-bit adapter */
+int init_cx18_i2c(struct cx18 *cx);
+void exit_cx18_i2c(struct cx18 *cx);
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c
new file mode 100644
index 000000000..f008604f9
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.c
@@ -0,0 +1,878 @@
+/*
+ * cx18 ioctl system call
+ *
+ * Derived from ivtv-ioctl.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-version.h"
+#include "cx18-mailbox.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-fileops.h"
+#include "cx18-vbi.h"
+#include "cx18-audio.h"
+#include "cx18-video.h"
+#include "cx18-streams.h"
+#include "cx18-ioctl.h"
+#include "cx18-gpio.h"
+#include "cx18-controls.h"
+#include "cx18-cards.h"
+#include "cx18-av-core.h"
+#include <media/tveeprom.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/i2c-id.h>
+
+u16 cx18_service2vbi(int type)
+{
+ switch (type) {
+ case V4L2_SLICED_TELETEXT_B:
+ return CX18_SLICED_TYPE_TELETEXT_B;
+ case V4L2_SLICED_CAPTION_525:
+ return CX18_SLICED_TYPE_CAPTION_525;
+ case V4L2_SLICED_WSS_625:
+ return CX18_SLICED_TYPE_WSS_625;
+ case V4L2_SLICED_VPS:
+ return CX18_SLICED_TYPE_VPS;
+ default:
+ return 0;
+ }
+}
+
+static int valid_service_line(int field, int line, int is_pal)
+{
+ return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
+ (!is_pal && line >= 10 && line < 22);
+}
+
+static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
+{
+ u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
+ int i;
+
+ set = set & valid_set;
+ if (set == 0 || !valid_service_line(field, line, is_pal))
+ return 0;
+ if (!is_pal) {
+ if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
+ return V4L2_SLICED_CAPTION_525;
+ } else {
+ if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
+ return V4L2_SLICED_VPS;
+ if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
+ return V4L2_SLICED_WSS_625;
+ if (line == 23)
+ return 0;
+ }
+ for (i = 0; i < 32; i++) {
+ if ((1 << i) & set)
+ return 1 << i;
+ }
+ return 0;
+}
+
+void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+ u16 set = fmt->service_set;
+ int f, l;
+
+ fmt->service_set = 0;
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++)
+ fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
+ }
+}
+
+static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+ int f, l;
+ u16 set = 0;
+
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
+ set |= fmt->service_lines[f][l];
+ }
+ }
+ return set != 0;
+}
+
+u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
+{
+ int f, l;
+ u16 set = 0;
+
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++)
+ set |= fmt->service_lines[f][l];
+ }
+ return set;
+}
+
+static const struct {
+ v4l2_std_id std;
+ char *name;
+} enum_stds[] = {
+ { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
+ { V4L2_STD_PAL_DK, "PAL-DK" },
+ { V4L2_STD_PAL_I, "PAL-I" },
+ { V4L2_STD_PAL_M, "PAL-M" },
+ { V4L2_STD_PAL_N, "PAL-N" },
+ { V4L2_STD_PAL_Nc, "PAL-Nc" },
+ { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
+ { V4L2_STD_SECAM_DK, "SECAM-DK" },
+ { V4L2_STD_SECAM_L, "SECAM-L" },
+ { V4L2_STD_SECAM_LC, "SECAM-L'" },
+ { V4L2_STD_NTSC_M, "NTSC-M" },
+ { V4L2_STD_NTSC_M_JP, "NTSC-J" },
+ { V4L2_STD_NTSC_M_KR, "NTSC-K" },
+};
+
+static const struct v4l2_standard cx18_std_60hz = {
+ .frameperiod = {.numerator = 1001, .denominator = 30000},
+ .framelines = 525,
+};
+
+static const struct v4l2_standard cx18_std_50hz = {
+ .frameperiod = { .numerator = 1, .denominator = 25 },
+ .framelines = 625,
+};
+
+static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct v4l2_register *regs = arg;
+ unsigned long flags;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cx18_cards_lock, flags);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ regs->val = read_enc(regs->reg);
+ else
+ write_enc(regs->val, regs->reg);
+ spin_unlock_irqrestore(&cx18_cards_lock, flags);
+ return 0;
+}
+
+static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt)
+{
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ fmt->fmt.pix.width = cx->params.width;
+ fmt->fmt.pix.height = cx->params.height;
+ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ if (streamtype == CX18_ENC_STREAM_TYPE_YUV) {
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+ /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ fmt->fmt.pix.sizeimage =
+ fmt->fmt.pix.height * fmt->fmt.pix.width +
+ fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
+ } else {
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ fmt->fmt.pix.sizeimage = 128 * 1024;
+ }
+ break;
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ fmt->fmt.vbi.sampling_rate = 27000000;
+ fmt->fmt.vbi.offset = 248;
+ fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+ fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ fmt->fmt.vbi.start[0] = cx->vbi.start[0];
+ fmt->fmt.vbi.start[1] = cx->vbi.start[1];
+ fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count;
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ {
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+ memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+
+ cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
+ vbifmt->service_set = cx18_get_service_set(vbifmt);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
+ struct v4l2_format *fmt, int set_fmt)
+{
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ u16 set;
+
+ /* set window size */
+ if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
+
+ if (w > 720)
+ w = 720;
+ else if (w < 1)
+ w = 1;
+ if (h > (cx->is_50hz ? 576 : 480))
+ h = (cx->is_50hz ? 576 : 480);
+ else if (h < 2)
+ h = 2;
+ cx18_get_fmt(cx, streamtype, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
+ if (cx->params.width != 720 || cx->params.height != (cx->is_50hz ? 576 : 480))
+ cx->params.video_temporal_filter = 0;
+ else
+ cx->params.video_temporal_filter = 8;
+#endif
+
+ if (!set_fmt || (cx->params.width == w && cx->params.height == h))
+ return 0;
+ if (atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+
+ cx->params.width = w;
+ cx->params.height = h;
+ if (w != 720 || h != (cx->is_50hz ? 576 : 480))
+ cx->params.video_temporal_filter = 0;
+ else
+ cx->params.video_temporal_filter = 8;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ return cx18_get_fmt(cx, streamtype, fmt);
+ }
+
+ /* set raw VBI format */
+ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
+ cx->vbi.sliced_in->service_set &&
+ atomic_read(&cx->ana_capturing) > 0)
+ return -EBUSY;
+ if (set_fmt) {
+ cx->vbi.sliced_in->service_set = 0;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+ }
+ return cx18_get_fmt(cx, streamtype, fmt);
+ }
+
+ /* any else but sliced VBI capture is an error */
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+
+ /* TODO: implement sliced VBI, for now silently return 0 */
+ return 0;
+
+ /* set sliced VBI capture format */
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+
+ if (vbifmt->service_set)
+ cx18_expand_service_set(vbifmt, cx->is_50hz);
+ set = check_service_set(vbifmt, cx->is_50hz);
+ vbifmt->service_set = cx18_get_service_set(vbifmt);
+
+ if (!set_fmt)
+ return 0;
+ if (set == 0)
+ return -EINVAL;
+ if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
+ return -EBUSY;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+ return 0;
+}
+
+static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct v4l2_register *reg = arg;
+
+ switch (cmd) {
+ /* ioctls to allow direct access to the encoder registers for testing */
+ case VIDIOC_DBG_G_REGISTER:
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+
+ case VIDIOC_DBG_S_REGISTER:
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+
+ case VIDIOC_G_CHIP_IDENT: {
+ struct v4l2_chip_ident *chip = arg;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
+ struct v4l2_chip_ident *chip = arg;
+
+ chip->ident = V4L2_IDENT_CX23418;
+ }
+ return 0;
+ }
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+ return -EINVAL;
+ }
+
+ case VIDIOC_INT_S_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
+
+ cx18_audio_set_route(cx, route);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg)
+{
+ struct cx18_open_id *id = NULL;
+
+ if (filp)
+ id = (struct cx18_open_id *)filp->private_data;
+
+ switch (cmd) {
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p = arg;
+
+ *p = v4l2_prio_max(&cx->prio);
+ break;
+ }
+
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *prio = arg;
+
+ return v4l2_prio_change(&cx->prio, &id->prio, *prio);
+ }
+
+ case VIDIOC_QUERYCAP:{
+ struct v4l2_capability *vcap = arg;
+
+ memset(vcap, 0, sizeof(*vcap));
+ strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+ vcap->version = CX18_DRIVER_VERSION; /* version */
+ vcap->capabilities = cx->v4l2_cap; /* capabilities */
+
+ /* reserved.. must set to 0! */
+ vcap->reserved[0] = vcap->reserved[1] =
+ vcap->reserved[2] = vcap->reserved[3] = 0;
+ break;
+ }
+
+ case VIDIOC_ENUMAUDIO:{
+ struct v4l2_audio *vin = arg;
+
+ return cx18_get_audio_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_G_AUDIO:{
+ struct v4l2_audio *vin = arg;
+
+ vin->index = cx->audio_input;
+ return cx18_get_audio_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_S_AUDIO:{
+ struct v4l2_audio *vout = arg;
+
+ if (vout->index >= cx->nof_audio_inputs)
+ return -EINVAL;
+ cx->audio_input = vout->index;
+ cx18_audio_set_io(cx);
+ break;
+ }
+
+ case VIDIOC_ENUMINPUT:{
+ struct v4l2_input *vin = arg;
+
+ /* set it to defaults from our table */
+ return cx18_get_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_S_FMT: {
+ struct v4l2_format *fmt = arg;
+
+ return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT);
+ }
+
+ case VIDIOC_G_FMT: {
+ struct v4l2_format *fmt = arg;
+ int type = fmt->type;
+
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->type = type;
+ return cx18_get_fmt(cx, id->type, fmt);
+ }
+
+ case VIDIOC_CROPCAP: {
+ struct v4l2_cropcap *cropcap = arg;
+
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ cropcap->bounds.top = cropcap->bounds.left = 0;
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height = cx->is_50hz ? 576 : 480;
+ cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+ cropcap->defrect = cropcap->bounds;
+ return 0;
+ }
+
+ case VIDIOC_S_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_S_CROP, arg);
+ }
+
+ case VIDIOC_G_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_G_CROP, arg);
+ }
+
+ case VIDIOC_ENUM_FMT: {
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
+ { 0, 0, 0, 0 }
+ },
+ { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+ "MPEG", V4L2_PIX_FMT_MPEG,
+ { 0, 0, 0, 0 }
+ }
+ };
+ struct v4l2_fmtdesc *fmt = arg;
+ enum v4l2_buf_type type = fmt->type;
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (fmt->index > 1)
+ return -EINVAL;
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:{
+ *(int *)arg = cx->active_input;
+ break;
+ }
+
+ case VIDIOC_S_INPUT:{
+ int inp = *(int *)arg;
+
+ if (inp < 0 || inp >= cx->nof_inputs)
+ return -EINVAL;
+
+ if (inp == cx->active_input) {
+ CX18_DEBUG_INFO("Input unchanged\n");
+ break;
+ }
+ CX18_DEBUG_INFO("Changing input from %d to %d\n",
+ cx->active_input, inp);
+
+ cx->active_input = inp;
+ /* Set the audio input to whatever is appropriate for the
+ input type. */
+ cx->audio_input = cx->card->video_inputs[inp].audio_index;
+
+ /* prevent others from messing with the streams until
+ we're finished changing inputs. */
+ cx18_mute(cx);
+ cx18_video_set_io(cx);
+ cx18_audio_set_io(cx);
+ cx18_unmute(cx);
+ break;
+ }
+
+ case VIDIOC_G_FREQUENCY:{
+ struct v4l2_frequency *vf = arg;
+
+ if (vf->tuner != 0)
+ return -EINVAL;
+ cx18_call_i2c_clients(cx, cmd, arg);
+ break;
+ }
+
+ case VIDIOC_S_FREQUENCY:{
+ struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
+
+ if (vf.tuner != 0)
+ return -EINVAL;
+
+ cx18_mute(cx);
+ CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
+ cx18_call_i2c_clients(cx, cmd, &vf);
+ cx18_unmute(cx);
+ break;
+ }
+
+ case VIDIOC_ENUMSTD:{
+ struct v4l2_standard *vs = arg;
+ int idx = vs->index;
+
+ if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
+ return -EINVAL;
+
+ *vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
+ cx18_std_60hz : cx18_std_50hz;
+ vs->index = idx;
+ vs->id = enum_stds[idx].std;
+ strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
+ break;
+ }
+
+ case VIDIOC_G_STD:{
+ *(v4l2_std_id *) arg = cx->std;
+ break;
+ }
+
+ case VIDIOC_S_STD: {
+ v4l2_std_id std = *(v4l2_std_id *) arg;
+
+ if ((std & V4L2_STD_ALL) == 0)
+ return -EINVAL;
+
+ if (std == cx->std)
+ break;
+
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
+ atomic_read(&cx->ana_capturing) > 0) {
+ /* Switching standard would turn off the radio or mess
+ with already running streams, prevent that by
+ returning EBUSY. */
+ return -EBUSY;
+ }
+
+ cx->std = std;
+ cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
+ cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
+ cx->params.width = 720;
+ cx->params.height = cx->is_50hz ? 576 : 480;
+ cx->vbi.count = cx->is_50hz ? 18 : 12;
+ cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+ cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+ cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
+ CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std);
+
+ /* Tuner */
+ cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ break;
+ }
+
+ case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
+ struct v4l2_tuner *vt = arg;
+
+ if (vt->index != 0)
+ return -EINVAL;
+
+ cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
+ break;
+ }
+
+ case VIDIOC_G_TUNER: {
+ struct v4l2_tuner *vt = arg;
+
+ if (vt->index != 0)
+ return -EINVAL;
+
+ memset(vt, 0, sizeof(*vt));
+ cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_ANALOG_TV;
+ }
+ break;
+ }
+
+ case VIDIOC_G_SLICED_VBI_CAP: {
+ struct v4l2_sliced_vbi_cap *cap = arg;
+ int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+ int f, l;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ enum v4l2_buf_type type = cap->type;
+#else
+ enum v4l2_buf_type type = VIDIOC_G_SLICED_VBI_CAP;
+#endif
+
+ memset(cap, 0, sizeof(*cap));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
+ cap->type = type;
+#endif
+ if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ if (valid_service_line(f, l, cx->is_50hz))
+ cap->service_lines[f][l] = set;
+ }
+ }
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+#if 0
+ case VIDIOC_G_ENC_INDEX: {
+ struct v4l2_enc_idx *idx = arg;
+ int i;
+
+ idx->entries = (cx->pgm_info_write_idx + CX18_MAX_PGM_INDEX - cx->pgm_info_read_idx) %
+ CX18_MAX_PGM_INDEX;
+ if (idx->entries > V4L2_ENC_IDX_ENTRIES)
+ idx->entries = V4L2_ENC_IDX_ENTRIES;
+ for (i = 0; i < idx->entries; i++)
+ idx->entry[i] = cx->pgm_info[(cx->pgm_info_read_idx + i) % CX18_MAX_PGM_INDEX];
+ cx->pgm_info_read_idx = (cx->pgm_info_read_idx + idx->entries) % CX18_MAX_PGM_INDEX;
+ break;
+ }
+#endif
+ case VIDIOC_ENCODER_CMD:
+ case VIDIOC_TRY_ENCODER_CMD: {
+ struct v4l2_encoder_cmd *enc = arg;
+ int try = cmd == VIDIOC_TRY_ENCODER_CMD;
+
+ memset(&enc->raw, 0, sizeof(enc->raw));
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ return cx18_start_capture(id);
+
+ case V4L2_ENC_CMD_STOP:
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ if (try)
+ return 0;
+ cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+ return 0;
+
+ case V4L2_ENC_CMD_PAUSE:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ if (!atomic_read(&cx->ana_capturing))
+ return -EPERM;
+ if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_mute(cx);
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
+ break;
+
+ case V4L2_ENC_CMD_RESUME:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ if (!atomic_read(&cx->ana_capturing))
+ return -EPERM;
+ if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+ cx18_unmute(cx);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ {
+ struct v4l2_input vidin;
+ struct v4l2_audio audin;
+ int i;
+
+ CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
+ if (cx->hw_flags & CX18_HW_TVEEPROM) {
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+ }
+ cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+ cx18_get_input(cx, cx->active_input, &vidin);
+ cx18_get_audio_input(cx, cx->audio_input, &audin);
+ CX18_INFO("Video Input: %s\n", vidin.name);
+ CX18_INFO("Audio Input: %s\n", audin.name);
+ CX18_INFO("Tuner: %s\n",
+ test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?
+ "Radio" : "TV");
+ cx2341x_log_status(&cx->params, cx->name);
+ CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev == NULL || s->buffers == 0)
+ continue;
+ CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+ s->name, s->s_flags,
+ (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+ (s->buffers * s->buf_size) / 1024, s->buffers);
+ }
+ CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+ (long long)cx->mpg_data_received,
+ (long long)cx->vbi_data_inserted);
+ CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, void *arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ int ret;
+
+ /* check priority */
+ switch (cmd) {
+ case VIDIOC_S_CTRL:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_S_FMT:
+ case VIDIOC_S_CROP:
+ case VIDIOC_S_EXT_CTRLS:
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+ }
+
+ switch (cmd) {
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_G_CHIP_IDENT:
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ case VIDIOC_INT_RESET:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_debug_ioctls(filp, cmd, arg);
+
+ case VIDIOC_G_PRIORITY:
+ case VIDIOC_S_PRIORITY:
+ case VIDIOC_QUERYCAP:
+ case VIDIOC_ENUMINPUT:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_ENUM_FMT:
+ case VIDIOC_CROPCAP:
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_ENUMSTD:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_TUNER:
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_S_AUDIO:
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_G_SLICED_VBI_CAP:
+ case VIDIOC_LOG_STATUS:
+ case VIDIOC_G_ENC_INDEX:
+ case VIDIOC_ENCODER_CMD:
+ case VIDIOC_TRY_ENCODER_CMD:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_v4l2_ioctls(cx, filp, cmd, arg);
+
+ case VIDIOC_QUERYMENU:
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_S_CTRL:
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_control_ioctls(cx, cmd, arg);
+
+ case 0x00005401: /* Handle isatty() calls */
+ return -EINVAL;
+ default:
+ return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+ cx18_v4l2_do_ioctl);
+ }
+ return 0;
+}
+
+int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ int res;
+
+ mutex_lock(&cx->serialize_lock);
+ res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl);
+ mutex_unlock(&cx->serialize_lock);
+ return res;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.h b/linux/drivers/media/video/cx18/cx18-ioctl.h
new file mode 100644
index 000000000..9f4c7eb28
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.h
@@ -0,0 +1,30 @@
+/*
+ * cx18 ioctl system call
+ *
+ * Derived from ivtv-ioctl.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+u16 cx18_service2vbi(int type);
+void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
+ void *arg);
diff --git a/linux/drivers/media/video/cx18/cx18-irq.c b/linux/drivers/media/video/cx18/cx18-irq.c
new file mode 100644
index 000000000..25114a5cb
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-irq.c
@@ -0,0 +1,181 @@
+/*
+ * cx18 interrupt handling
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-firmware.h"
+#include "cx18-fileops.h"
+#include "cx18-queue.h"
+#include "cx18-irq.h"
+#include "cx18-ioctl.h"
+#include "cx18-mailbox.h"
+#include "cx18-vbi.h"
+#include "cx18-scb.h"
+
+#define DMA_MAGIC_COOKIE 0x000001fe
+
+static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
+{
+ u32 handle = mb->args[0];
+ struct cx18_stream *s = NULL;
+ struct cx18_buffer *buf;
+ u32 off;
+ int i;
+ int id;
+
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ s = &cx->streams[i];
+ if ((handle == s->handle) && (s->dvb.enabled))
+ break;
+ if (s->v4l2dev && handle == s->handle)
+ break;
+ }
+ if (i == CX18_MAX_STREAMS) {
+ CX18_WARN("DMA done for unknown handle %d for stream %s\n",
+ handle, s->name);
+ mb->error = CXERR_NOT_OPEN;
+ mb->cmd = 0;
+ cx18_mb_ack(cx, mb);
+ return;
+ }
+
+ off = mb->args[1];
+ if (mb->args[2] != 1)
+ CX18_WARN("Ack struct = %d for %s\n",
+ mb->args[2], s->name);
+ id = read_enc(off);
+ buf = cx18_queue_find_buf(s, id, read_enc(off + 4));
+ CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
+ if (buf) {
+ cx18_buf_sync_for_cpu(s, buf);
+ if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
+ /* process the buffer here */
+ CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
+ buf->bytesused);
+
+ dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
+ buf->bytesused);
+
+ cx18_buf_sync_for_device(s, buf);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ } else
+ set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ } else {
+ CX18_WARN("Could not find buf %d for stream %s\n",
+ read_enc(off), s->name);
+ }
+ mb->error = 0;
+ mb->cmd = 0;
+ cx18_mb_ack(cx, mb);
+ wake_up(&cx->dma_waitq);
+ if (s->id != -1)
+ wake_up(&s->waitq);
+}
+
+static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
+{
+ char str[256] = { 0 };
+ char *p;
+
+ if (mb->args[1]) {
+ setup_page(mb->args[1]);
+ memcpy_fromio(str, cx->enc_mem + mb->args[1], 252);
+ str[252] = 0;
+ }
+ cx18_mb_ack(cx, mb);
+ CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
+ p = strchr(str, '.');
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
+ CX18_INFO("FW version: %s\n", p - 1);
+}
+
+static void hpu_cmd(struct cx18 *cx, u32 sw1)
+{
+ struct cx18_mailbox mb;
+
+ if (sw1 & IRQ_CPU_TO_EPU) {
+ memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb));
+ mb.error = 0;
+
+ switch (mb.cmd) {
+ case CX18_EPU_DMA_DONE:
+ epu_dma_done(cx, &mb);
+ break;
+ case CX18_EPU_DEBUG:
+ epu_debug(cx, &mb);
+ break;
+ default:
+ CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd);
+ break;
+ }
+ }
+ if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU))
+ CX18_WARN("Unexpected interrupt %08x\n", sw1);
+}
+
+irqreturn_t cx18_irq_handler(int irq, void *dev_id)
+{
+ struct cx18 *cx = (struct cx18 *)dev_id;
+ u32 sw1, sw1_mask;
+ u32 sw2, sw2_mask;
+ u32 hw2, hw2_mask;
+
+ spin_lock(&cx->dma_reg_lock);
+
+ hw2_mask = read_reg(HW2_INT_MASK5_PCI);
+ hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask;
+ sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
+ sw2 = read_reg(SW2_INT_STATUS) & sw2_mask;
+ sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
+ sw1 = read_reg(SW1_INT_STATUS) & sw1_mask;
+
+ write_reg(sw2&sw2_mask, SW2_INT_STATUS);
+ write_reg(sw1&sw1_mask, SW1_INT_STATUS);
+ write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS);
+
+ if (sw1 || sw2 || hw2)
+ CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2);
+
+ /* To do: interrupt-based I2C handling
+ if (hw2 & 0x00c00000) {
+ }
+ */
+
+ if (sw2) {
+ if (sw2 & (readl(&cx->scb->cpu2hpu_irq_ack) |
+ readl(&cx->scb->cpu2epu_irq_ack)))
+ wake_up(&cx->mb_cpu_waitq);
+ if (sw2 & (readl(&cx->scb->apu2hpu_irq_ack) |
+ readl(&cx->scb->apu2epu_irq_ack)))
+ wake_up(&cx->mb_apu_waitq);
+ if (sw2 & readl(&cx->scb->epu2hpu_irq_ack))
+ wake_up(&cx->mb_epu_waitq);
+ if (sw2 & readl(&cx->scb->hpu2epu_irq_ack))
+ wake_up(&cx->mb_hpu_waitq);
+ }
+
+ if (sw1)
+ hpu_cmd(cx, sw1);
+ spin_unlock(&cx->dma_reg_lock);
+
+ return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-irq.h b/linux/drivers/media/video/cx18/cx18-irq.h
new file mode 100644
index 000000000..379f704f5
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-irq.h
@@ -0,0 +1,37 @@
+/*
+ * cx18 interrupt handling
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#define HW2_I2C1_INT (1 << 22)
+#define HW2_I2C2_INT (1 << 23)
+#define HW2_INT_CLR_STATUS 0xc730c4
+#define HW2_INT_MASK5_PCI 0xc730e4
+#define SW1_INT_SET 0xc73100
+#define SW1_INT_STATUS 0xc73104
+#define SW1_INT_ENABLE_PCI 0xc7311c
+#define SW2_INT_SET 0xc73140
+#define SW2_INT_STATUS 0xc73144
+#define SW2_INT_ENABLE_PCI 0xc7315c
+
+irqreturn_t cx18_irq_handler(int irq, void *dev_id);
+
+void cx18_irq_work_handler(struct work_struct *work);
+void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock);
+void cx18_unfinished_dma(unsigned long arg);
diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c
new file mode 100644
index 000000000..2a5ccef91
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.c
@@ -0,0 +1,372 @@
+/*
+ * cx18 mailbox functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "cx18-driver.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-mailbox.h"
+
+#define API_FAST (1 << 2) /* Short timeout */
+#define API_SLOW (1 << 3) /* Additional 300ms timeout */
+
+#define APU 0
+#define CPU 1
+#define EPU 2
+#define HPU 3
+
+struct cx18_api_info {
+ u32 cmd;
+ u8 flags; /* Flags, see above */
+ u8 rpu; /* Processing unit */
+ const char *name; /* The name of the command */
+};
+
+#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x }
+
+static const struct cx18_api_info api_info[] = {
+ /* MPEG encoder API */
+ API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
+ API_ENTRY(CPU, CX18_EPU_DEBUG, 0),
+ API_ENTRY(CPU, CX18_CREATE_TASK, 0),
+ API_ENTRY(CPU, CX18_DESTROY_TASK, 0),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
+ API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
+ API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
+ API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
+ API_ENTRY(0, 0, 0),
+};
+
+static const struct cx18_api_info *find_api_info(u32 cmd)
+{
+ int i;
+
+ for (i = 0; api_info[i].cmd; i++)
+ if (api_info[i].cmd == cmd)
+ return &api_info[i];
+ return NULL;
+}
+
+static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu,
+ u32 *state, u32 *irq, u32 *req)
+{
+ struct cx18_mailbox __iomem *mb = NULL;
+ int wait_count = 0;
+ u32 ack;
+
+ switch (rpu) {
+ case APU:
+ mb = &cx->scb->epu2apu_mb;
+ *state = readl(&cx->scb->apu_state);
+ *irq = readl(&cx->scb->epu2apu_irq);
+ break;
+
+ case CPU:
+ mb = &cx->scb->epu2cpu_mb;
+ *state = readl(&cx->scb->cpu_state);
+ *irq = readl(&cx->scb->epu2cpu_irq);
+ break;
+
+ case HPU:
+ mb = &cx->scb->epu2hpu_mb;
+ *state = readl(&cx->scb->hpu_state);
+ *irq = readl(&cx->scb->epu2hpu_irq);
+ break;
+ }
+
+ if (mb == NULL)
+ return mb;
+
+ do {
+ *req = readl(&mb->request);
+ ack = readl(&mb->ack);
+ wait_count++;
+ } while (*req != ack && wait_count < 600);
+
+ if (*req == ack) {
+ (*req)++;
+ if (*req == 0 || *req == 0xffffffff)
+ *req = 1;
+ return mb;
+ }
+ return NULL;
+}
+
+long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
+{
+ const struct cx18_api_info *info = find_api_info(mb->cmd);
+ struct cx18_mailbox __iomem *ack_mb;
+ u32 ack_irq;
+ u8 rpu = CPU;
+
+ if (info == NULL && mb->cmd) {
+ CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
+ return -EINVAL;
+ }
+ if (info)
+ rpu = info->rpu;
+
+ switch (rpu) {
+ case HPU:
+ ack_irq = IRQ_EPU_TO_HPU_ACK;
+ ack_mb = &cx->scb->hpu2epu_mb;
+ break;
+ case APU:
+ ack_irq = IRQ_EPU_TO_APU_ACK;
+ ack_mb = &cx->scb->apu2epu_mb;
+ break;
+ case CPU:
+ ack_irq = IRQ_EPU_TO_CPU_ACK;
+ ack_mb = &cx->scb->cpu2epu_mb;
+ break;
+ default:
+ CX18_WARN("Unknown RPU for command %x\n", mb->cmd);
+ return -EINVAL;
+ }
+
+ setup_page(SCB_OFFSET);
+ write_sync(mb->request, &ack_mb->ack);
+ write_reg(ack_irq, SW2_INT_SET);
+ return 0;
+}
+
+
+static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
+{
+ const struct cx18_api_info *info = find_api_info(cmd);
+ u32 state = 0, irq = 0, req, oldreq, err;
+ struct cx18_mailbox __iomem *mb;
+ wait_queue_head_t *waitq;
+ int timeout = 100;
+ int cnt = 0;
+ int sig = 0;
+ int i;
+
+ if (info == NULL) {
+ CX18_WARN("unknown cmd %x\n", cmd);
+ return -EINVAL;
+ }
+
+ if (cmd == CX18_CPU_DE_SET_MDL)
+ CX18_DEBUG_HI_API("%s\n", info->name);
+ else
+ CX18_DEBUG_API("%s\n", info->name);
+ setup_page(SCB_OFFSET);
+ mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
+
+ if (mb == NULL) {
+ CX18_ERR("mb %s busy\n", info->name);
+ return -EBUSY;
+ }
+
+ oldreq = req - 1;
+ writel(cmd, &mb->cmd);
+ for (i = 0; i < args; i++)
+ writel(data[i], &mb->args[i]);
+ writel(0, &mb->error);
+ writel(req, &mb->request);
+
+ switch (info->rpu) {
+ case APU: waitq = &cx->mb_apu_waitq; break;
+ case CPU: waitq = &cx->mb_cpu_waitq; break;
+ case EPU: waitq = &cx->mb_epu_waitq; break;
+ case HPU: waitq = &cx->mb_hpu_waitq; break;
+ default: return -EINVAL;
+ }
+ if (info->flags & API_FAST)
+ timeout /= 2;
+ write_reg(irq, SW1_INT_SET);
+
+ while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) {
+ if (cnt > 200 && !in_atomic())
+ sig = cx18_msleep_timeout(10, 1);
+ cnt++;
+ }
+ if (sig)
+ return -EINTR;
+ if (cnt == 660) {
+ writel(oldreq, &mb->request);
+ CX18_ERR("mb %s failed\n", info->name);
+ return -EINVAL;
+ }
+ for (i = 0; i < MAX_MB_ARGUMENTS; i++)
+ data[i] = readl(&mb->args[i]);
+ err = readl(&mb->error);
+ if (!in_atomic() && (info->flags & API_SLOW))
+ cx18_msleep_timeout(300, 0);
+ if (err)
+ CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
+ info->name);
+ return err ? -EIO : 0;
+}
+
+int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
+{
+ int res = cx18_api_call(cx, cmd, args, data);
+
+ /* Allow a single retry, probably already too late though.
+ If there is no free mailbox then that is usually an indication
+ of a more serious problem. */
+ return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res;
+}
+
+static int cx18_set_filter_param(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ u32 mode;
+ int ret;
+
+ mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0);
+ ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 1, mode, cx->spatial_strength);
+ mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0);
+ ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 0, mode, cx->temporal_strength);
+ ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 2, cx->filter_mode >> 2, 0);
+ return ret;
+}
+
+int cx18_api_func(void *priv, u32 cmd, int in, int out,
+ u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ struct cx18 *cx = priv;
+ struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+
+ switch (cmd) {
+ case CX2341X_ENC_SET_OUTPUT_PORT:
+ return 0;
+ case CX2341X_ENC_SET_FRAME_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6,
+ s->handle, 0, 0, 0, 0, data[0]);
+ case CX2341X_ENC_SET_FRAME_SIZE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3,
+ s->handle, data[1], data[0]);
+ case CX2341X_ENC_SET_STREAM_TYPE:
+ return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_ASPECT_RATIO:
+ return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2,
+ s->handle, data[0]);
+
+ case CX2341X_ENC_SET_GOP_PROPERTIES:
+ return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3,
+ s->handle, data[0], data[1]);
+ case CX2341X_ENC_SET_GOP_CLOSURE:
+ return 0;
+ case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+ return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_MUTE_AUDIO:
+ return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_BIT_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5,
+ s->handle, data[0], data[1], data[2], data[3]);
+ case CX2341X_ENC_MUTE_VIDEO:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_FRAME_DROP_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_MISC:
+ return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4,
+ s->handle, data[0], data[1], data[2]);
+ case CX2341X_ENC_SET_DNR_FILTER_MODE:
+ cx->filter_mode = (data[0] & 3) | (data[1] << 2);
+ return cx18_set_filter_param(s);
+ case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+ cx->spatial_strength = data[0];
+ cx->temporal_strength = data[1];
+ return cx18_set_filter_param(s);
+ case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+ return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3,
+ s->handle, data[0], data[1]);
+ case CX2341X_ENC_SET_CORING_LEVELS:
+ return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5,
+ s->handle, data[0], data[1], data[2], data[3]);
+ }
+ CX18_WARN("Unknown cmd %x\n", cmd);
+ return 0;
+}
+
+int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS],
+ u32 cmd, int args, ...)
+{
+ va_list ap;
+ int i;
+
+ va_start(ap, args);
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(ap, u32);
+ va_end(ap);
+ return cx18_api(cx, cmd, args, data);
+}
+
+int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...)
+{
+ u32 data[MAX_MB_ARGUMENTS];
+ va_list ap;
+ int i;
+
+ if (cx == NULL) {
+ CX18_ERR("cx == NULL (cmd=%x)\n", cmd);
+ return 0;
+ }
+ if (args > MAX_MB_ARGUMENTS) {
+ CX18_ERR("args too big (cmd=%x)\n", cmd);
+ args = MAX_MB_ARGUMENTS;
+ }
+ va_start(ap, args);
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(ap, u32);
+ va_end(ap);
+ return cx18_api(cx, cmd, args, data);
+}
diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.h b/linux/drivers/media/video/cx18/cx18-mailbox.h
new file mode 100644
index 000000000..d99564153
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.h
@@ -0,0 +1,73 @@
+/*
+ * cx18 mailbox functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef _CX18_MAILBOX_H_
+#define _CX18_MAILBOX_H_
+
+/* mailbox max args */
+#define MAX_MB_ARGUMENTS 6
+/* compatibility, should be same as the define in cx2341x.h */
+#define CX2341X_MBOX_MAX_DATA 16
+
+#define MB_RESERVED_HANDLE_0 0
+#define MB_RESERVED_HANDLE_1 0xFFFFFFFF
+
+struct cx18;
+
+/* The cx18_mailbox struct is the mailbox structure which is used for passing
+ messages between processors */
+struct cx18_mailbox {
+ /* The sender sets a handle in 'request' after he fills the command. The
+ 'request' should be different than 'ack'. The sender, also, generates
+ an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the
+ receiver. */
+ u32 request;
+ /* The receiver detects a new command when 'req' is different than 'ack'.
+ He sets 'ack' to the same value as 'req' to clear the command. He, also,
+ generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU
+ is the receiver. */
+ u32 ack;
+ u32 reserved[6];
+ /* 'cmd' identifies the command. The list of these commands are in
+ cx23418.h */
+ u32 cmd;
+ /* Each command can have up to 6 arguments */
+ u32 args[MAX_MB_ARGUMENTS];
+ /* The return code can be one of the codes in the file cx23418.h. If the
+ command is completed successfuly, the error will be ERR_SYS_SUCCESS.
+ If it is pending, the code is ERR_SYS_PENDING. If it failed, the error
+ code would indicate the task from which the error originated and will
+ be one of the errors in cx23418.h. In that case, the following
+ applies ((error & 0xff) != 0).
+ If the command is pending, the return will be passed in a MB from the
+ receiver to the sender. 'req' will be returned in args[0] */
+ u32 error;
+};
+
+int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
+int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
+ int args, ...);
+int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...);
+int cx18_api_func(void *priv, u32 cmd, int in, int out,
+ u32 data[CX2341X_MBOX_MAX_DATA]);
+long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb);
+
+#endif
diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c
new file mode 100644
index 000000000..6990b77c6
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-queue.c
@@ -0,0 +1,272 @@
+/*
+ * cx18 buffer queues
+ *
+ * Derived from ivtv-queue.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-streams.h"
+#include "cx18-queue.h"
+#include "cx18-scb.h"
+
+void cx18_buf_swap(struct cx18_buffer *buf)
+{
+ int i;
+
+ for (i = 0; i < buf->bytesused; i += 4)
+ swab32s((u32 *)(buf->buf + i));
+}
+
+void cx18_queue_init(struct cx18_queue *q)
+{
+ INIT_LIST_HEAD(&q->list);
+ q->buffers = 0;
+ q->length = 0;
+ q->bytesused = 0;
+}
+
+void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q)
+{
+ unsigned long flags = 0;
+
+ /* clear the buffer if it is going to be enqueued to the free queue */
+ if (q == &s->q_free) {
+ buf->bytesused = 0;
+ buf->readpos = 0;
+ buf->b_flags = 0;
+ }
+ spin_lock_irqsave(&s->qlock, flags);
+ list_add_tail(&buf->list, &q->list);
+ q->buffers++;
+ q->length += s->buf_size;
+ q->bytesused += buf->bytesused - buf->readpos;
+ spin_unlock_irqrestore(&s->qlock, flags);
+}
+
+struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
+{
+ struct cx18_buffer *buf = NULL;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&s->qlock, flags);
+ if (!list_empty(&q->list)) {
+ buf = list_entry(q->list.next, struct cx18_buffer, list);
+ list_del_init(q->list.next);
+ q->buffers--;
+ q->length -= s->buf_size;
+ q->bytesused -= buf->bytesused - buf->readpos;
+ }
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return buf;
+}
+
+struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+ u32 bytesused)
+{
+ struct cx18 *cx = s->cx;
+ struct list_head *p;
+
+ list_for_each(p, &s->q_free.list) {
+ struct cx18_buffer *buf =
+ list_entry(p, struct cx18_buffer, list);
+
+ if (buf->id != id)
+ continue;
+ buf->bytesused = bytesused;
+ /* the transport buffers are handled differently,
+ so there is no need to move them to the full queue */
+ if (s->type == CX18_ENC_STREAM_TYPE_TS)
+ return buf;
+ s->q_free.buffers--;
+ s->q_free.length -= s->buf_size;
+ s->q_full.buffers++;
+ s->q_full.length += s->buf_size;
+ s->q_full.bytesused += buf->bytesused;
+ list_move_tail(&buf->list, &s->q_full.list);
+ return buf;
+ }
+ CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
+ return NULL;
+}
+
+static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from,
+ struct cx18_queue *to, int clear, int full)
+{
+ struct cx18_buffer *buf =
+ list_entry(from->list.next, struct cx18_buffer, list);
+
+ list_move_tail(from->list.next, &to->list);
+ from->buffers--;
+ from->length -= s->buf_size;
+ from->bytesused -= buf->bytesused - buf->readpos;
+ /* special handling for q_free */
+ if (clear)
+ buf->bytesused = buf->readpos = buf->b_flags = 0;
+ else if (full) {
+ /* special handling for stolen buffers, assume
+ all bytes are used. */
+ buf->bytesused = s->buf_size;
+ buf->readpos = buf->b_flags = 0;
+ }
+ to->buffers++;
+ to->length += s->buf_size;
+ to->bytesused += buf->bytesused - buf->readpos;
+}
+
+/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
+ If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
+ If 'steal' != NULL, then buffers may also taken from that queue if
+ needed.
+
+ The buffer is automatically cleared if it goes to the free queue. It is
+ also cleared if buffers need to be taken from the 'steal' queue and
+ the 'from' queue is the free queue.
+
+ When 'from' is q_free, then needed_bytes is compared to the total
+ available buffer length, otherwise needed_bytes is compared to the
+ bytesused value. For the 'steal' queue the total available buffer
+ length is always used.
+
+ -ENOMEM is returned if the buffers could not be obtained, 0 if all
+ buffers where obtained from the 'from' list and if non-zero then
+ the number of stolen buffers is returned. */
+static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
+ struct cx18_queue *steal, struct cx18_queue *to,
+ int needed_bytes)
+{
+ unsigned long flags;
+ int rc = 0;
+ int from_free = from == &s->q_free;
+ int to_free = to == &s->q_free;
+ int bytes_available;
+
+ spin_lock_irqsave(&s->qlock, flags);
+ if (needed_bytes == 0) {
+ from_free = 1;
+ needed_bytes = from->length;
+ }
+
+ bytes_available = from_free ? from->length : from->bytesused;
+ bytes_available += steal ? steal->length : 0;
+
+ if (bytes_available < needed_bytes) {
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return -ENOMEM;
+ }
+ if (from_free) {
+ u32 old_length = to->length;
+
+ while (to->length - old_length < needed_bytes) {
+ if (list_empty(&from->list))
+ from = steal;
+ if (from == steal)
+ rc++; /* keep track of 'stolen' buffers */
+ cx18_queue_move_buf(s, from, to, 1, 0);
+ }
+ } else {
+ u32 old_bytesused = to->bytesused;
+
+ while (to->bytesused - old_bytesused < needed_bytes) {
+ if (list_empty(&from->list))
+ from = steal;
+ if (from == steal)
+ rc++; /* keep track of 'stolen' buffers */
+ cx18_queue_move_buf(s, from, to, to_free, rc);
+ }
+ }
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return rc;
+}
+
+void cx18_flush_queues(struct cx18_stream *s)
+{
+ cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
+ cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+}
+
+int cx18_stream_alloc(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ int i;
+
+ if (s->buffers == 0)
+ return 0;
+
+ CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n",
+ s->name, s->buffers, s->buf_size,
+ s->buffers * s->buf_size / 1024);
+
+ if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
+ (char *)cx->scb) > SCB_RESERVED_SIZE) {
+ unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE -
+ ((char *)cx->scb->cpu_mdl));
+
+ CX18_ERR("Too many buffers, cannot fit in SCB area\n");
+ CX18_ERR("Max buffers = %zd\n",
+ bufsz / sizeof(struct cx18_mdl));
+ return -ENOMEM;
+ }
+
+ s->mdl_offset = cx->mdl_offset;
+
+ /* allocate stream buffers. Initially all buffers are in q_free. */
+ for (i = 0; i < s->buffers; i++) {
+ struct cx18_buffer *buf = kzalloc(sizeof(struct cx18_buffer),
+ GFP_KERNEL|__GFP_NOWARN);
+
+ if (buf == NULL)
+ break;
+ buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN);
+ if (buf->buf == NULL) {
+ kfree(buf);
+ break;
+ }
+ buf->id = cx->buffer_id++;
+ INIT_LIST_HEAD(&buf->list);
+ buf->dma_handle = pci_map_single(s->cx->dev,
+ buf->buf, s->buf_size, s->dma);
+ cx18_buf_sync_for_cpu(s, buf);
+ cx18_enqueue(s, buf, &s->q_free);
+ }
+ if (i == s->buffers) {
+ cx->mdl_offset += s->buffers;
+ return 0;
+ }
+ CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name);
+ cx18_stream_free(s);
+ return -ENOMEM;
+}
+
+void cx18_stream_free(struct cx18_stream *s)
+{
+ struct cx18_buffer *buf;
+
+ /* move all buffers to q_free */
+ cx18_flush_queues(s);
+
+ /* empty q_free */
+ while ((buf = cx18_dequeue(s, &s->q_free))) {
+ pci_unmap_single(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+ kfree(buf->buf);
+ kfree(buf);
+ }
+}
diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h
new file mode 100644
index 000000000..91423b986
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-queue.h
@@ -0,0 +1,55 @@
+/*
+ * cx18 buffer queues
+ *
+ * Derived from ivtv-queue.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#define CX18_DMA_UNMAPPED ((u32) -1)
+
+/* cx18_buffer utility functions */
+
+static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+{
+ pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+}
+
+static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+{
+ pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+}
+
+void cx18_buf_swap(struct cx18_buffer *buf);
+
+/* cx18_queue utility functions */
+void cx18_queue_init(struct cx18_queue *q);
+void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q);
+struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
+struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+ u32 bytesused);
+void cx18_flush_queues(struct cx18_stream *s);
+
+/* cx18_stream utility functions */
+int cx18_stream_alloc(struct cx18_stream *s);
+void cx18_stream_free(struct cx18_stream *s);
diff --git a/linux/drivers/media/video/cx18/cx18-scb.c b/linux/drivers/media/video/cx18/cx18-scb.c
new file mode 100644
index 000000000..30bc803e3
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-scb.c
@@ -0,0 +1,121 @@
+/*
+ * cx18 System Control Block initialization
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-scb.h"
+
+void cx18_init_scb(struct cx18 *cx)
+{
+ setup_page(SCB_OFFSET);
+ memset_io(cx->scb, 0, 0x10000);
+
+ writel(IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq);
+ writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
+ writel(IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq);
+ writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq);
+ writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq);
+ writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq);
+ writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
+ writel(IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq);
+ writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq);
+ writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq);
+ writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq);
+ writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
+ writel(IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq);
+ writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
+ writel(IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq);
+ writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq);
+ writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq);
+ writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
+ writel(IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq);
+ writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
+ writel(IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq);
+ writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
+ writel(IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq);
+ writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq);
+ writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
+ writel(IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq);
+ writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
+ writel(IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq);
+ writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq);
+ writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
+
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
+ &cx->scb->apu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
+ &cx->scb->hpu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
+ &cx->scb->ppu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
+ &cx->scb->epu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
+ &cx->scb->cpu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
+ &cx->scb->hpu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
+ &cx->scb->ppu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
+ &cx->scb->epu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
+ &cx->scb->cpu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
+ &cx->scb->apu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
+ &cx->scb->ppu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
+ &cx->scb->epu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
+ &cx->scb->cpu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
+ &cx->scb->apu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
+ &cx->scb->hpu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
+ &cx->scb->epu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
+ &cx->scb->cpu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
+ &cx->scb->apu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
+ &cx->scb->hpu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
+ &cx->scb->ppu2epu_mb_offset);
+
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
+ &cx->scb->ipc_offset);
+
+ writel(1, &cx->scb->hpu_state);
+ writel(1, &cx->scb->epu_state);
+}
diff --git a/linux/drivers/media/video/cx18/cx18-scb.h b/linux/drivers/media/video/cx18/cx18-scb.h
new file mode 100644
index 000000000..86b4cb15d
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-scb.h
@@ -0,0 +1,285 @@
+/*
+ * cx18 System Control Block initialization
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef CX18_SCB_H
+#define CX18_SCB_H
+
+#include "cx18-mailbox.h"
+
+/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts
+ are in the SW1 register. */
+
+#define IRQ_APU_TO_CPU 0x00000001
+#define IRQ_CPU_TO_APU_ACK 0x00000001
+#define IRQ_HPU_TO_CPU 0x00000002
+#define IRQ_CPU_TO_HPU_ACK 0x00000002
+#define IRQ_PPU_TO_CPU 0x00000004
+#define IRQ_CPU_TO_PPU_ACK 0x00000004
+#define IRQ_EPU_TO_CPU 0x00000008
+#define IRQ_CPU_TO_EPU_ACK 0x00000008
+
+#define IRQ_CPU_TO_APU 0x00000010
+#define IRQ_APU_TO_CPU_ACK 0x00000010
+#define IRQ_HPU_TO_APU 0x00000020
+#define IRQ_APU_TO_HPU_ACK 0x00000020
+#define IRQ_PPU_TO_APU 0x00000040
+#define IRQ_APU_TO_PPU_ACK 0x00000040
+#define IRQ_EPU_TO_APU 0x00000080
+#define IRQ_APU_TO_EPU_ACK 0x00000080
+
+#define IRQ_CPU_TO_HPU 0x00000100
+#define IRQ_HPU_TO_CPU_ACK 0x00000100
+#define IRQ_APU_TO_HPU 0x00000200
+#define IRQ_HPU_TO_APU_ACK 0x00000200
+#define IRQ_PPU_TO_HPU 0x00000400
+#define IRQ_HPU_TO_PPU_ACK 0x00000400
+#define IRQ_EPU_TO_HPU 0x00000800
+#define IRQ_HPU_TO_EPU_ACK 0x00000800
+
+#define IRQ_CPU_TO_PPU 0x00001000
+#define IRQ_PPU_TO_CPU_ACK 0x00001000
+#define IRQ_APU_TO_PPU 0x00002000
+#define IRQ_PPU_TO_APU_ACK 0x00002000
+#define IRQ_HPU_TO_PPU 0x00004000
+#define IRQ_PPU_TO_HPU_ACK 0x00004000
+#define IRQ_EPU_TO_PPU 0x00008000
+#define IRQ_PPU_TO_EPU_ACK 0x00008000
+
+#define IRQ_CPU_TO_EPU 0x00010000
+#define IRQ_EPU_TO_CPU_ACK 0x00010000
+#define IRQ_APU_TO_EPU 0x00020000
+#define IRQ_EPU_TO_APU_ACK 0x00020000
+#define IRQ_HPU_TO_EPU 0x00040000
+#define IRQ_EPU_TO_HPU_ACK 0x00040000
+#define IRQ_PPU_TO_EPU 0x00080000
+#define IRQ_EPU_TO_PPU_ACK 0x00080000
+
+#define SCB_OFFSET 0xDC0000
+
+/* If Firmware uses fixed memory map, it shall not allocate the area
+ between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */
+#define SCB_RESERVED_SIZE 0x10000
+
+
+/* This structure is used by EPU to provide memory descriptors in its memory */
+struct cx18_mdl {
+ u32 paddr; /* Physical address of a buffer segment */
+ u32 length; /* Length of the buffer segment */
+};
+
+/* This structure is used by CPU to provide completed buffers information */
+struct cx18_mdl_ack {
+ u32 id; /* ID of a completed MDL */
+ u32 data_used; /* Total data filled in the MDL for buffer 'id' */
+};
+
+struct cx18_scb {
+ /* These fields form the System Control Block which is used at boot time
+ for localizing the IPC data as well as the code positions for all
+ processors. The offsets are from the start of this struct. */
+
+ /* Offset where to find the Inter-Processor Communication data */
+ u32 ipc_offset;
+ u32 reserved01[7];
+ /* Offset where to find the start of the CPU code */
+ u32 cpu_code_offset;
+ u32 reserved02[3];
+ /* Offset where to find the start of the APU code */
+ u32 apu_code_offset;
+ u32 reserved03[3];
+ /* Offset where to find the start of the HPU code */
+ u32 hpu_code_offset;
+ u32 reserved04[3];
+ /* Offset where to find the start of the PPU code */
+ u32 ppu_code_offset;
+ u32 reserved05[3];
+
+ /* These fields form Inter-Processor Communication data which is used
+ by all processors to locate the information needed for communicating
+ with other processors */
+
+ /* Fields for CPU: */
+
+ /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */
+ u32 cpu_state;
+ u32 reserved1[7];
+ /* Offset to the mailbox used for sending commands from APU to CPU */
+ u32 apu2cpu_mb_offset;
+ /* Value to write to register SW1 register set (0xC7003100) after the
+ command is ready */
+ u32 apu2cpu_irq;
+ /* Value to write to register SW2 register set (0xC7003140) after the
+ command is cleared */
+ u32 apu2cpu_irq_ack;
+ u32 reserved2[13];
+
+ u32 hpu2cpu_mb_offset;
+ u32 hpu2cpu_irq;
+ u32 hpu2cpu_irq_ack;
+ u32 reserved3[13];
+
+ u32 ppu2cpu_mb_offset;
+ u32 ppu2cpu_irq;
+ u32 ppu2cpu_irq_ack;
+ u32 reserved4[13];
+
+ u32 epu2cpu_mb_offset;
+ u32 epu2cpu_irq;
+ u32 epu2cpu_irq_ack;
+ u32 reserved5[13];
+ u32 reserved6[8];
+
+ /* Fields for APU: */
+
+ u32 apu_state;
+ u32 reserved11[7];
+ u32 cpu2apu_mb_offset;
+ u32 cpu2apu_irq;
+ u32 cpu2apu_irq_ack;
+ u32 reserved12[13];
+
+ u32 hpu2apu_mb_offset;
+ u32 hpu2apu_irq;
+ u32 hpu2apu_irq_ack;
+ u32 reserved13[13];
+
+ u32 ppu2apu_mb_offset;
+ u32 ppu2apu_irq;
+ u32 ppu2apu_irq_ack;
+ u32 reserved14[13];
+
+ u32 epu2apu_mb_offset;
+ u32 epu2apu_irq;
+ u32 epu2apu_irq_ack;
+ u32 reserved15[13];
+ u32 reserved16[8];
+
+ /* Fields for HPU: */
+
+ u32 hpu_state;
+ u32 reserved21[7];
+ u32 cpu2hpu_mb_offset;
+ u32 cpu2hpu_irq;
+ u32 cpu2hpu_irq_ack;
+ u32 reserved22[13];
+
+ u32 apu2hpu_mb_offset;
+ u32 apu2hpu_irq;
+ u32 apu2hpu_irq_ack;
+ u32 reserved23[13];
+
+ u32 ppu2hpu_mb_offset;
+ u32 ppu2hpu_irq;
+ u32 ppu2hpu_irq_ack;
+ u32 reserved24[13];
+
+ u32 epu2hpu_mb_offset;
+ u32 epu2hpu_irq;
+ u32 epu2hpu_irq_ack;
+ u32 reserved25[13];
+ u32 reserved26[8];
+
+ /* Fields for PPU: */
+
+ u32 ppu_state;
+ u32 reserved31[7];
+ u32 cpu2ppu_mb_offset;
+ u32 cpu2ppu_irq;
+ u32 cpu2ppu_irq_ack;
+ u32 reserved32[13];
+
+ u32 apu2ppu_mb_offset;
+ u32 apu2ppu_irq;
+ u32 apu2ppu_irq_ack;
+ u32 reserved33[13];
+
+ u32 hpu2ppu_mb_offset;
+ u32 hpu2ppu_irq;
+ u32 hpu2ppu_irq_ack;
+ u32 reserved34[13];
+
+ u32 epu2ppu_mb_offset;
+ u32 epu2ppu_irq;
+ u32 epu2ppu_irq_ack;
+ u32 reserved35[13];
+ u32 reserved36[8];
+
+ /* Fields for EPU: */
+
+ u32 epu_state;
+ u32 reserved41[7];
+ u32 cpu2epu_mb_offset;
+ u32 cpu2epu_irq;
+ u32 cpu2epu_irq_ack;
+ u32 reserved42[13];
+
+ u32 apu2epu_mb_offset;
+ u32 apu2epu_irq;
+ u32 apu2epu_irq_ack;
+ u32 reserved43[13];
+
+ u32 hpu2epu_mb_offset;
+ u32 hpu2epu_irq;
+ u32 hpu2epu_irq_ack;
+ u32 reserved44[13];
+
+ u32 ppu2epu_mb_offset;
+ u32 ppu2epu_irq;
+ u32 ppu2epu_irq_ack;
+ u32 reserved45[13];
+ u32 reserved46[8];
+
+ u32 semaphores[8]; /* Semaphores */
+
+ u32 reserved50[32]; /* Reserved for future use */
+
+ struct cx18_mailbox apu2cpu_mb;
+ struct cx18_mailbox hpu2cpu_mb;
+ struct cx18_mailbox ppu2cpu_mb;
+ struct cx18_mailbox epu2cpu_mb;
+
+ struct cx18_mailbox cpu2apu_mb;
+ struct cx18_mailbox hpu2apu_mb;
+ struct cx18_mailbox ppu2apu_mb;
+ struct cx18_mailbox epu2apu_mb;
+
+ struct cx18_mailbox cpu2hpu_mb;
+ struct cx18_mailbox apu2hpu_mb;
+ struct cx18_mailbox ppu2hpu_mb;
+ struct cx18_mailbox epu2hpu_mb;
+
+ struct cx18_mailbox cpu2ppu_mb;
+ struct cx18_mailbox apu2ppu_mb;
+ struct cx18_mailbox hpu2ppu_mb;
+ struct cx18_mailbox epu2ppu_mb;
+
+ struct cx18_mailbox cpu2epu_mb;
+ struct cx18_mailbox apu2epu_mb;
+ struct cx18_mailbox hpu2epu_mb;
+ struct cx18_mailbox ppu2epu_mb;
+
+ struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][2];
+ struct cx18_mdl cpu_mdl[1];
+};
+
+void cx18_init_scb(struct cx18 *cx);
+
+#endif
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
new file mode 100644
index 000000000..7f695f36a
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -0,0 +1,603 @@
+/*
+ * cx18 init/start/stop/exit stream functions
+ *
+ * Derived from ivtv-streams.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-fileops.h"
+#include "cx18-mailbox.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-ioctl.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "cx18-scb.h"
+#include "cx18-av-core.h"
+#include "cx18-dvb.h"
+
+#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
+
+static struct file_operations cx18_v4l2_enc_fops = {
+ .owner = THIS_MODULE,
+ .read = cx18_v4l2_read,
+ .open = cx18_v4l2_open,
+ .ioctl = cx18_v4l2_ioctl,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+ .compat_ioctl = v4l_compat_ioctl32,
+#endif
+ .release = cx18_v4l2_close,
+ .poll = cx18_v4l2_enc_poll,
+};
+
+/* offset from 0 to register ts v4l2 minors on */
+#define CX18_V4L2_ENC_TS_OFFSET 16
+/* offset from 0 to register pcm v4l2 minors on */
+#define CX18_V4L2_ENC_PCM_OFFSET 24
+/* offset from 0 to register yuv v4l2 minors on */
+#define CX18_V4L2_ENC_YUV_OFFSET 32
+
+static struct {
+ const char *name;
+ int vfl_type;
+ int minor_offset;
+ int dma;
+ enum v4l2_buf_type buf_type;
+ struct file_operations *fops;
+} cx18_stream_info[] = {
+ { /* CX18_ENC_STREAM_TYPE_MPG */
+ "encoder MPEG",
+ VFL_TYPE_GRABBER, 0,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_TS */
+ "TS",
+ VFL_TYPE_GRABBER, -1,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_YUV */
+ "encoder YUV",
+ VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_VBI */
+ "encoder VBI",
+ VFL_TYPE_VBI, 0,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_PCM */
+ "encoder PCM audio",
+ VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_IDX */
+ "encoder IDX",
+ VFL_TYPE_GRABBER, -1,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_RAD */
+ "encoder radio",
+ VFL_TYPE_RADIO, 0,
+ PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE,
+ &cx18_v4l2_enc_fops
+ },
+};
+
+static void cx18_stream_init(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ struct video_device *dev = s->v4l2dev;
+ u32 max_size = cx->options.megabytes[type] * 1024 * 1024;
+
+ /* we need to keep v4l2dev, so restore it afterwards */
+ memset(s, 0, sizeof(*s));
+ s->v4l2dev = dev;
+
+ /* initialize cx18_stream fields */
+ s->cx = cx;
+ s->type = type;
+ s->name = cx18_stream_info[type].name;
+ s->handle = 0xffffffff;
+
+ s->dma = cx18_stream_info[type].dma;
+ s->buf_size = cx->stream_buf_size[type];
+ if (s->buf_size)
+ s->buffers = max_size / s->buf_size;
+ if (s->buffers > 63) {
+ /* Each stream has a maximum of 63 buffers,
+ ensure we do not exceed that. */
+ s->buffers = 63;
+ s->buf_size = (max_size / s->buffers) & ~0xfff;
+ }
+ spin_lock_init(&s->qlock);
+ init_waitqueue_head(&s->waitq);
+ s->id = -1;
+ cx18_queue_init(&s->q_free);
+ cx18_queue_init(&s->q_full);
+ cx18_queue_init(&s->q_io);
+}
+
+static int cx18_prep_dev(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ u32 cap = cx->v4l2_cap;
+ int minor_offset = cx18_stream_info[type].minor_offset;
+ int minor;
+
+ /* These four fields are always initialized. If v4l2dev == NULL, then
+ this stream is not in use. In that case no other fields but these
+ four can be used. */
+ s->v4l2dev = NULL;
+ s->cx = cx;
+ s->type = type;
+ s->name = cx18_stream_info[type].name;
+
+ /* Check whether the radio is supported */
+ if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO))
+ return 0;
+
+ /* Check whether VBI is supported */
+ if (type == CX18_ENC_STREAM_TYPE_VBI &&
+ !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
+ return 0;
+
+ /* card number + user defined offset + device offset */
+ minor = cx->num + cx18_first_minor + minor_offset;
+
+ /* User explicitly selected 0 buffers for these streams, so don't
+ create them. */
+ if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
+ cx->options.megabytes[type] == 0) {
+ CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
+ return 0;
+ }
+
+ cx18_stream_init(cx, type);
+
+ if (minor_offset == -1)
+ return 0;
+
+ /* allocate and initialize the v4l2 video device structure */
+ s->v4l2dev = video_device_alloc();
+ if (s->v4l2dev == NULL) {
+ CX18_ERR("Couldn't allocate v4l2 video_device for %s\n",
+ s->name);
+ return -ENOMEM;
+ }
+
+ s->v4l2dev->type =
+ VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |
+ VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;
+ snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s",
+ cx->num, s->name);
+
+ s->v4l2dev->minor = minor;
+ s->v4l2dev->dev = &cx->dev->dev;
+ s->v4l2dev->fops = cx18_stream_info[type].fops;
+ s->v4l2dev->release = video_device_release;
+
+ return 0;
+}
+
+/* Initialize v4l2 variables and register v4l2 devices */
+int cx18_streams_setup(struct cx18 *cx)
+{
+ int type;
+
+ /* Setup V4L2 Devices */
+ for (type = 0; type < CX18_MAX_STREAMS; type++) {
+ /* Prepare device */
+ if (cx18_prep_dev(cx, type))
+ break;
+
+ /* Allocate Stream */
+ if (cx18_stream_alloc(&cx->streams[type]))
+ break;
+ }
+ if (type == CX18_MAX_STREAMS)
+ return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ cx18_streams_cleanup(cx, 0);
+ return -ENOMEM;
+}
+
+static int cx18_reg_dev(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ int vfl_type = cx18_stream_info[type].vfl_type;
+ int minor;
+
+ /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
+ * We need a VFL_TYPE_TS defined.
+ */
+ if (strcmp("TS", s->name) == 0) {
+ /* just return if no DVB is supported */
+ if ((cx->card->hw_all & CX18_HW_DVB) == 0)
+ return 0;
+ if (cx18_dvb_register(s) < 0) {
+ CX18_ERR("DVB failed to register\n");
+ return -EINVAL;
+ }
+ }
+
+ if (s->v4l2dev == NULL)
+ return 0;
+
+ minor = s->v4l2dev->minor;
+
+ /* Register device. First try the desired minor, then any free one. */
+ if (video_register_device(s->v4l2dev, vfl_type, minor) &&
+ video_register_device(s->v4l2dev, vfl_type, -1)) {
+ CX18_ERR("Couldn't register v4l2 device for %s minor %d\n",
+ s->name, minor);
+ video_device_release(s->v4l2dev);
+ s->v4l2dev = NULL;
+ return -ENOMEM;
+ }
+ minor = s->v4l2dev->minor;
+
+ switch (vfl_type) {
+ case VFL_TYPE_GRABBER:
+ CX18_INFO("Registered device video%d for %s (%d MB)\n",
+ minor, s->name, cx->options.megabytes[type]);
+ break;
+
+ case VFL_TYPE_RADIO:
+ CX18_INFO("Registered device radio%d for %s\n",
+ minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
+ break;
+
+ case VFL_TYPE_VBI:
+ if (cx->options.megabytes[type])
+ CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
+ minor - MINOR_VFL_TYPE_VBI_MIN,
+ s->name, cx->options.megabytes[type]);
+ else
+ CX18_INFO("Registered device vbi%d for %s\n",
+ minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
+ break;
+ }
+
+ return 0;
+}
+
+/* Register v4l2 devices */
+int cx18_streams_register(struct cx18 *cx)
+{
+ int type;
+ int err = 0;
+
+ /* Register V4L2 devices */
+ for (type = 0; type < CX18_MAX_STREAMS; type++)
+ err |= cx18_reg_dev(cx, type);
+
+ if (err == 0)
+ return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ cx18_streams_cleanup(cx, 1);
+ return -ENOMEM;
+}
+
+/* Unregister v4l2 devices */
+void cx18_streams_cleanup(struct cx18 *cx, int unregister)
+{
+ struct video_device *vdev;
+ int type;
+
+ /* Teardown all streams */
+ for (type = 0; type < CX18_MAX_STREAMS; type++) {
+ if (cx->streams[type].dvb.enabled)
+ cx18_dvb_unregister(&cx->streams[type]);
+
+ vdev = cx->streams[type].v4l2dev;
+
+ cx->streams[type].v4l2dev = NULL;
+ if (vdev == NULL)
+ continue;
+
+ cx18_stream_free(&cx->streams[type]);
+
+ /* Unregister or release device */
+ if (unregister)
+ video_unregister_device(vdev);
+ else
+ video_device_release(vdev);
+ }
+}
+
+static void cx18_vbi_setup(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ int raw = cx->vbi.sliced_in->service_set == 0;
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ int lines;
+
+ if (cx->is_60hz) {
+ cx->vbi.count = 12;
+ cx->vbi.start[0] = 10;
+ cx->vbi.start[1] = 273;
+ } else { /* PAL/SECAM */
+ cx->vbi.count = 18;
+ cx->vbi.start[0] = 6;
+ cx->vbi.start[1] = 318;
+ }
+
+ /* setup VBI registers */
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+
+ /* determine number of lines and total number of VBI bytes.
+ A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
+ The '- 1' byte is probably an unused U or V byte. Or something...
+ A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
+ header, 42 data bytes + checksum (to be confirmed) */
+ if (raw) {
+ lines = cx->vbi.count * 2;
+ } else {
+ lines = cx->is_60hz ? 24 : 38;
+ if (cx->is_60hz)
+ lines += 2;
+ }
+
+ cx->vbi.enc_size = lines *
+ (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+
+ data[0] = s->handle;
+ /* Lines per field */
+ data[1] = (lines / 2) | ((lines / 2) << 16);
+ /* bytes per line */
+ data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+ /* Every X number of frames a VBI interrupt arrives
+ (frames as in 25 or 30 fps) */
+ data[3] = 1;
+ /* Setup VBI for the cx25840 digitizer */
+ if (raw) {
+ data[4] = 0x20602060;
+ data[5] = 0x30703070;
+ } else {
+ data[4] = 0xB0F0B0F0;
+ data[5] = 0xA0E0A0E0;
+ }
+
+ CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI)
+ cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
+}
+
+int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+{
+ u32 data[MAX_MB_ARGUMENTS];
+ struct cx18 *cx = s->cx;
+ struct list_head *p;
+ int ts = 0;
+ int captype = 0;
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ return -EINVAL;
+
+ CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
+
+ switch (s->type) {
+ case CX18_ENC_STREAM_TYPE_MPG:
+ captype = CAPTURE_CHANNEL_TYPE_MPEG;
+ cx->mpg_data_received = cx->vbi_data_inserted = 0;
+ cx->dualwatch_jiffies = jiffies;
+ cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300;
+ cx->search_pack_header = 0;
+ break;
+
+ case CX18_ENC_STREAM_TYPE_TS:
+ captype = CAPTURE_CHANNEL_TYPE_TS;
+ ts = 1;
+ break;
+ case CX18_ENC_STREAM_TYPE_YUV:
+ captype = CAPTURE_CHANNEL_TYPE_YUV;
+ break;
+ case CX18_ENC_STREAM_TYPE_PCM:
+ captype = CAPTURE_CHANNEL_TYPE_PCM;
+ break;
+ case CX18_ENC_STREAM_TYPE_VBI:
+ captype = cx->vbi.sliced_in->service_set ?
+ CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI;
+ cx->vbi.frame = 0;
+ cx->vbi.inserted_frame = 0;
+ memset(cx->vbi.sliced_mpeg_size,
+ 0, sizeof(cx->vbi.sliced_mpeg_size));
+ break;
+ default:
+ return -EINVAL;
+ }
+ s->buffers_stolen = 0;
+
+ /* mute/unmute video */
+ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
+ s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags));
+
+ /* Clear Streamoff flags in case left from last capture */
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+ cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE);
+ s->handle = data[0];
+ cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
+
+ if (atomic_read(&cx->ana_capturing) == 0 && !ts) {
+ /* Stuff from Windows, we don't know what it is */
+ cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12);
+
+ cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
+ s->handle, cx->digitizer, cx->digitizer);
+
+ /* Setup VBI */
+ if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
+ cx18_vbi_setup(s);
+
+ /* assign program index info.
+ Mask 7: select I/P/B, Num_req: 400 max */
+ cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
+
+ /* Setup API for Stream */
+ cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
+ }
+
+ if (atomic_read(&cx->tot_capturing) == 0) {
+ clear_bit(CX18_F_I_EOS, &cx->i_flags);
+ write_reg(7, CX18_DSP0_INTERRUPT_MASK);
+ }
+
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
+ (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
+ (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
+
+ list_for_each(p, &s->q_free.list) {
+ struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
+
+ writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr);
+ writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ }
+ /* begin_capture */
+ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
+ CX18_DEBUG_WARN("Error starting capture!\n");
+ cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+ return -EINVAL;
+ }
+
+ /* you're live! sit back and await interrupts :) */
+ if (!ts)
+ atomic_inc(&cx->ana_capturing);
+ atomic_inc(&cx->tot_capturing);
+ return 0;
+}
+
+void cx18_stop_all_captures(struct cx18 *cx)
+{
+ int i;
+
+ for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ continue;
+ if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
+ cx18_stop_v4l2_encode_stream(s, 0);
+ }
+}
+
+int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
+{
+ struct cx18 *cx = s->cx;
+ unsigned long then;
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ return -EINVAL;
+
+ /* This function assumes that you are allowed to stop the capture
+ and that we are actually capturing */
+
+ CX18_DEBUG_INFO("Stop Capture\n");
+
+ if (atomic_read(&cx->tot_capturing) == 0)
+ return 0;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
+ else
+ cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+
+ then = jiffies;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
+#if 0
+ /* only run these if we're shutting down the last cap */
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long duration;
+
+ then = jiffies;
+ add_wait_queue(&cx->cap_w, &wait);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /* TODO: wait 2s for EOS interrupt */
+ while (!test_bit(CX18_F_I_EOS, &cx->i_flags) &&
+ time_before(jiffies, then + msecs_to_jiffies(2000)))
+ schedule_timeout(msecs_to_jiffies(10));
+
+ duration = jiffies_to_msecs(jiffies - then);
+
+ if (!test_bit(CX18_F_I_EOS, &cx->i_flags)) {
+ CX18_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name);
+ CX18_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration);
+ } else {
+ CX18_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&cx->cap_w, &wait);
+#else
+ CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
+#endif
+ }
+
+ if (s->type != CX18_ENC_STREAM_TYPE_TS)
+ atomic_dec(&cx->ana_capturing);
+ atomic_dec(&cx->tot_capturing);
+
+ /* Clear capture and no-read bits */
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+
+ cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+ s->handle = 0xffffffff;
+
+ if (atomic_read(&cx->tot_capturing) > 0)
+ return 0;
+
+ write_reg(5, CX18_DSP0_INTERRUPT_MASK);
+ wake_up(&s->waitq);
+
+ return 0;
+}
+
+u32 cx18_find_handle(struct cx18 *cx)
+{
+ int i;
+
+ /* find first available handle to be used for global settings */
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev && s->handle)
+ return s->handle;
+ }
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-streams.h b/linux/drivers/media/video/cx18/cx18-streams.h
new file mode 100644
index 000000000..f327e947b
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-streams.h
@@ -0,0 +1,33 @@
+/*
+ * cx18 init/start/stop/exit stream functions
+ *
+ * Derived from ivtv-streams.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+u32 cx18_find_handle(struct cx18 *cx);
+int cx18_streams_setup(struct cx18 *cx);
+int cx18_streams_register(struct cx18 *cx);
+void cx18_streams_cleanup(struct cx18 *cx, int unregister);
+
+/* Capture related */
+int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
+int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
+
+void cx18_stop_all_captures(struct cx18 *cx);
diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c
new file mode 100644
index 000000000..22e76ee3f
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-vbi.c
@@ -0,0 +1,208 @@
+/*
+ * cx18 Vertical Blank Interval support functions
+ *
+ * Derived from ivtv-vbi.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-vbi.h"
+#include "cx18-ioctl.h"
+#include "cx18-queue.h"
+#include "cx18-av-core.h"
+
+static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
+{
+ int line = 0;
+ int i;
+ u32 linemask[2] = { 0, 0 };
+ unsigned short size;
+ static const u8 mpeg_hdr_data[] = {
+ 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
+ 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
+ 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
+ 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
+ };
+ const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
+ int idx = cx->vbi.frame % CX18_VBI_FRAMES;
+ u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0];
+
+ for (i = 0; i < lines; i++) {
+ struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i;
+ int f, l;
+
+ if (sdata->id == 0)
+ continue;
+
+ l = sdata->line - 6;
+ f = sdata->field;
+ if (f)
+ l += 18;
+ if (l < 32)
+ linemask[0] |= (1 << l);
+ else
+ linemask[1] |= (1 << (l - 32));
+ dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id);
+ memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42);
+ line++;
+ }
+ memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
+ if (line == 36) {
+ /* All lines are used, so there is no space for the linemask
+ (the max size of the VBI data is 36 * 43 + 4 bytes).
+ So in this case we use the magic number 'ITV0'. */
+ memcpy(dst + sd, "ITV0", 4);
+ memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+ size = 4 + ((43 * line + 3) & ~3);
+ } else {
+ memcpy(dst + sd, "cx0", 4);
+ memcpy(dst + sd + 4, &linemask[0], 8);
+ size = 12 + ((43 * line + 3) & ~3);
+ }
+ dst[4+16] = (size + 10) >> 8;
+ dst[5+16] = (size + 10) & 0xff;
+ dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
+ dst[10+16] = (pts_stamp >> 22) & 0xff;
+ dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
+ dst[12+16] = (pts_stamp >> 7) & 0xff;
+ dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
+ cx->vbi.sliced_mpeg_size[idx] = sd + size;
+}
+
+/* Compress raw VBI format, removes leading SAV codes and surplus space
+ after the field.
+ Returns new compressed size. */
+static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
+{
+ u32 line_size = cx->vbi.raw_decoder_line_size;
+ u32 lines = cx->vbi.count;
+ u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
+ u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
+ u8 *q = buf;
+ u8 *p;
+ int i;
+
+ for (i = 0; i < lines; i++) {
+ p = buf + i * line_size;
+
+ /* Look for SAV code */
+ if (p[0] != 0xff || p[1] || p[2] ||
+ (p[3] != sav1 && p[3] != sav2))
+ break;
+ memcpy(q, p + 4, line_size - 4);
+ q += line_size - 4;
+ }
+ return lines * (line_size - 4);
+}
+
+
+/* Compressed VBI format, all found sliced blocks put next to one another
+ Returns new compressed size */
+static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
+ u32 size, u8 sav)
+{
+ u32 line_size = cx->vbi.sliced_decoder_line_size;
+ struct v4l2_decode_vbi_line vbi;
+ int i;
+
+ /* find the first valid line */
+ for (i = 0; i < size; i++, buf++) {
+ if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
+ break;
+ }
+
+ size -= i;
+ if (size < line_size)
+ return line;
+ for (i = 0; i < size / line_size; i++) {
+ u8 *p = buf + i * line_size;
+
+ /* Look for SAV code */
+ if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
+ continue;
+ vbi.p = p + 4;
+ cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
+ if (vbi.type) {
+ cx->vbi.sliced_data[line].id = vbi.type;
+ cx->vbi.sliced_data[line].field = vbi.is_second_field;
+ cx->vbi.sliced_data[line].line = vbi.line;
+ memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42);
+ line++;
+ }
+ }
+ return line;
+}
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+ u64 pts_stamp, int streamtype)
+{
+ u8 *p = (u8 *) buf->buf;
+ u32 size = buf->bytesused;
+ int lines;
+
+ if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
+ return;
+
+ /* Raw VBI data */
+ if (cx->vbi.sliced_in->service_set == 0) {
+ u8 type;
+
+ cx18_buf_swap(buf);
+
+ type = p[3];
+
+ size = buf->bytesused = compress_raw_buf(cx, p, size);
+
+ /* second field of the frame? */
+ if (type == cx->vbi.raw_decoder_sav_even_field) {
+ /* Dirty hack needed for backwards
+ compatibility of old VBI software. */
+ p += size - 4;
+ memcpy(p, &cx->vbi.frame, 4);
+ cx->vbi.frame++;
+ }
+ return;
+ }
+
+ /* Sliced VBI data with data insertion */
+ cx18_buf_swap(buf);
+
+ /* first field */
+ lines = compress_sliced_buf(cx, 0, p, size / 2,
+ cx->vbi.sliced_decoder_sav_odd_field);
+ /* second field */
+ /* experimentation shows that the second half does not always
+ begin at the exact address. So start a bit earlier
+ (hence 32). */
+ lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
+ size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field);
+ /* always return at least one empty line */
+ if (lines == 0) {
+ cx->vbi.sliced_data[0].id = 0;
+ cx->vbi.sliced_data[0].line = 0;
+ cx->vbi.sliced_data[0].field = 0;
+ lines = 1;
+ }
+ buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]);
+ memcpy(p, &cx->vbi.sliced_data[0], size);
+
+ if (cx->vbi.insert_mpeg)
+ copy_vbi_data(cx, lines, pts_stamp);
+ cx->vbi.frame++;
+}
diff --git a/linux/drivers/media/video/cx18/cx18-vbi.h b/linux/drivers/media/video/cx18/cx18-vbi.h
new file mode 100644
index 000000000..c56ff7d28
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-vbi.h
@@ -0,0 +1,26 @@
+/*
+ * cx18 Vertical Blank Interval support functions
+ *
+ * Derived from ivtv-vbi.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+ u64 pts_stamp, int streamtype);
+int cx18_used_line(struct cx18 *cx, int line, int field);
diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h
new file mode 100644
index 000000000..d5c7a6f96
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-version.h
@@ -0,0 +1,34 @@
+/*
+ * cx18 driver version information
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef CX18_VERSION_H
+#define CX18_VERSION_H
+
+#define CX18_DRIVER_NAME "cx18"
+#define CX18_DRIVER_VERSION_MAJOR 1
+#define CX18_DRIVER_VERSION_MINOR 0
+#define CX18_DRIVER_VERSION_PATCHLEVEL 0
+
+#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
+#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
+ CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL)
+
+#endif
diff --git a/linux/drivers/media/video/cx18/cx18-video.c b/linux/drivers/media/video/cx18/cx18-video.c
new file mode 100644
index 000000000..2e5c41939
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-video.c
@@ -0,0 +1,45 @@
+/*
+ * cx18 video interface functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-video.h"
+#include "cx18-av-core.h"
+#include "cx18-cards.h"
+
+void cx18_video_set_io(struct cx18 *cx)
+{
+ struct v4l2_routing route;
+ int inp = cx->active_input;
+ u32 type;
+
+ route.input = cx->card->video_inputs[inp].video_input;
+ route.output = 0;
+ cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+ type = cx->card->video_inputs[inp].video_type;
+
+ if (type == CX18_CARD_INPUT_VID_TUNER)
+ route.input = 0; /* Tuner */
+ else if (type < CX18_CARD_INPUT_COMPOSITE1)
+ route.input = 2; /* S-Video */
+ else
+ route.input = 1; /* Composite */
+}
diff --git a/linux/drivers/media/video/cx18/cx18-video.h b/linux/drivers/media/video/cx18/cx18-video.h
new file mode 100644
index 000000000..529006a06
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx18-video.h
@@ -0,0 +1,22 @@
+/*
+ * cx18 video interface functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+void cx18_video_set_io(struct cx18 *cx);
diff --git a/linux/drivers/media/video/cx18/cx23418.h b/linux/drivers/media/video/cx18/cx23418.h
new file mode 100644
index 000000000..33f78da9d
--- /dev/null
+++ b/linux/drivers/media/video/cx18/cx23418.h
@@ -0,0 +1,458 @@
+/*
+ * cx18 header containing common defines.
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef CX23418_H
+#define CX23418_H
+
+#include <media/cx2341x.h>
+
+#define MGR_CMD_MASK 0x40000000
+/* The MSB of the command code indicates that this is the completion of a
+ command */
+#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000)
+
+/* Description: This command creates a new instance of a certain task
+ IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is
+ the processor on which the task YYY will be created
+ OUT[0] - Task handle. This handle is passed along with commands to
+ dispatch to the right instance of the task
+ ReturnCode - One of the ERR_SYS_... */
+#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001)
+
+/* Description: This command destroys an instance of a task
+ IN[0] - Task handle. Hanlde of the task to destroy
+ ReturnCode - One of the ERR_SYS_... */
+#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002)
+
+/* All commands for CPU have the following mask set */
+#define CPU_CMD_MASK 0x20000000
+#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000)
+#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000)
+#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000)
+
+#define EPU_CMD_MASK 0x02000000
+#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000)
+#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000)
+
+/* Description: This command indicates that a Memory Descriptor List has been
+ filled with the requested channel type
+ IN[0] - Task handle. Handle of the task
+ IN[1] - Offset of the MDL_ACK from the beginning of the local DDR.
+ IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1]
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001)
+
+/* Something interesting happened
+ IN[0] - A value to log
+ IN[1] - An offset of a string in the MiniMe memory;
+ 0/zero/NULL means "I have nothing to say" */
+#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003)
+
+/* Description: This command starts streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to start
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002)
+
+/* Description: This command stops streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to stop
+ IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only)
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003)
+
+/* Description: This command pauses streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to pause
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007)
+
+/* Description: This command resumes streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to resume
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008)
+
+#define CAPTURE_CHANNEL_TYPE_NONE 0
+#define CAPTURE_CHANNEL_TYPE_MPEG 1
+#define CAPTURE_CHANNEL_TYPE_INDEX 2
+#define CAPTURE_CHANNEL_TYPE_YUV 3
+#define CAPTURE_CHANNEL_TYPE_PCM 4
+#define CAPTURE_CHANNEL_TYPE_VBI 5
+#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6
+#define CAPTURE_CHANNEL_TYPE_TS 7
+#define CAPTURE_CHANNEL_TYPE_MAX 15
+
+/* Description: This command sets the channel type. This can only be done
+ when stopped.
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Channel Type. See Below.
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1)
+
+/* Description: Set stream output type
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - type
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012)
+
+/* Description: Set video input resolution and frame rate
+ IN[0] - task handle
+ IN[1] - reserved
+ IN[2] - reserved
+ IN[3] - reserved
+ IN[4] - reserved
+ IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004)
+
+/* Description: Set video frame rate
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - video bit rate mode
+ IN[2] - video average rate
+ IN[3] - video peak rate
+ IN[4] - system mux rate
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005)
+
+/* Description: Set video output resolution
+ IN[0] - task handle
+ IN[1] - horizontal size
+ IN[2] - vertical size
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006)
+
+/* Description: This command set filter parameters
+ IN[0] - Task handle. Handle of the task
+ IN[1] - type, 0 - temporal, 1 - spatial, 2 - median
+ IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic
+ median: 0 = disable, 1 = horizontal, 2 = vertical,
+ 3 = horizontal/vertical, 4 = diagonal
+ IN[3] - strength, temporal 0 - 31, spatial 0 - 15
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009)
+
+/* Description: This command set spatial filter type
+ IN[0] - Task handle.
+ IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only,
+ 3 = 2D H/V separable, 4 = 2D symmetric non-separable
+ IN[2] - chroma type: 0 - diable, 1 = 1D horizontal
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C)
+
+/* Description: This command set coring levels for median filter
+ IN[0] - Task handle.
+ IN[1] - luma_high
+ IN[2] - luma_low
+ IN[3] - chroma_high
+ IN[4] - chroma_low
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E)
+
+/* Description: This command set the picture type mask for index file
+ IN[0] - 0 = disable index file output
+ 1 = output I picture
+ 2 = P picture
+ 4 = B picture
+ other = illegal */
+#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010)
+
+/* Description: Set audio parameters
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - audio parameter
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011)
+
+/* Description: Set video mute
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - bit31-24: muteYvalue
+ bit23-16: muteUvalue
+ bit15-8: muteVvalue
+ bit0: 1:mute, 0: unmute
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013)
+
+/* Description: Set audio mute
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - mute/unmute
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014)
+
+/* Description: Set stream output type
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - subType
+ SET_INITIAL_SCR 1
+ SET_QUALITY_MODE 2
+ SET_VIM_PROTECT_MODE 3
+ SET_PTS_CORRECTION 4
+ SET_USB_FLUSH_MODE 5
+ SET_MERAQPAR_ENABLE 6
+ SET_NAV_PACK_INSERTION 7
+ SET_SCENE_CHANGE_ENABLE 8
+ IN[2] - parameter 1
+ IN[3] - parameter 2
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015)
+
+/* Description: Set raw VBI parameters
+ IN[0] - Task handle
+ IN[1] - No. of input lines per field:
+ bit[15:0]: field 1,
+ bit[31:16]: field 2
+ IN[2] - No. of input bytes per line
+ IN[3] - No. of output frames per transfer
+ IN[4] - start code
+ IN[5] - stop code
+ ReturnCode */
+#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016)
+
+/* Description: Set capture line No.
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - height1
+ IN[2] - height2
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017)
+
+/* Description: Set copyright
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - copyright
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018)
+
+/* Description: Set audio PID
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - PID
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019)
+
+/* Description: Set video PID
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - PID
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A)
+
+/* Description: Set Vertical Crop Line
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - Line
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B)
+
+/* Description: Set COP structure
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - M
+ IN[2] - N
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C)
+
+/* Description: Set Scene Change Detection
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - scene change
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D)
+
+/* Description: Set Aspect Ratio
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - AspectRatio
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E)
+
+/* Description: Set Skip Input Frame
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - skip input frames
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F)
+
+/* Description: Set sliced VBI parameters -
+ Note This API will only apply to MPEG and Sliced VBI Channels
+ IN[0] - Task handle
+ IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext
+ IN[2] - start / stop line
+ bit[15:0] start line number
+ bit[31:16] stop line number
+ IN[3] - number of output frames per interrupt
+ IN[4] - VBI insertion mode
+ bit 0: output user data, 1 - enable
+ bit 1: output private stream, 1 - enable
+ bit 2: mux option, 0 - in GOP, 1 - in picture
+ bit[7:0] private stream ID
+ IN[5] - insertion period while mux option is in picture
+ ReturnCode - VBI data offset */
+#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020)
+
+/* Description: Set the user data place holder
+ IN[0] - type of data (0 for user)
+ IN[1] - Stuffing period
+ IN[2] - ID data size in word (less than 10)
+ IN[3] - Pointer to ID buffer */
+#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021)
+
+
+/* Description:
+ In[0] Task Handle
+ return parameter:
+ Out[0] Reserved
+ Out[1] Video PTS bit[32:2] of last output video frame.
+ Out[2] Video PTS bit[ 1:0] of last output video frame.
+ Out[3] Hardware Video PTS counter bit[31:0],
+ these bits get incremented on every 90kHz clock tick.
+ Out[4] Hardware Video PTS counter bit32,
+ these bits get incremented on every 90kHz clock tick.
+ ReturnCode */
+#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022)
+
+/* Below is the list of commands related to the data exchange */
+#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000)
+
+/* Description: This command provides the physical base address of the local
+ DDR as viewed by EPU
+ IN[0] - Physical offset where EPU has the local DDR mapped
+ ReturnCode - One of the ERR_DE_... */
+#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001)
+
+/* Description: This command provides the offsets in the device memory where
+ the 2 cx18_mdl_ack blocks reside
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Offset of the first cx18_mdl_ack from the beginning of the
+ local DDR.
+ IN[2] - Offset of the second cx18_mdl_ack from the beginning of the
+ local DDR.
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002)
+
+/* Description: This command provides the offset to a Memory Descriptor List
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Offset of the MDL from the beginning of the local DDR.
+ IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1]
+ IN[3] - Buffer ID
+ IN[4] - Total buffer length
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005)
+
+/* Description: This command requests return of all current Memory
+ Descriptor Lists to the driver
+ IN[0] - Task handle. Handle of the task to start
+ ReturnCode - One of the ERR_DE_... */
+/* #define CX18_CPU_DE_ReleaseMDL (CPU_CMD_MASK_DE | 0x0006) */
+
+/* Description: This command signals the cpu that the dat buffer has been
+ consumed and ready for re-use.
+ IN[0] - Task handle. Handle of the task
+ IN[1] - Offset of the data block from the beginning of the local DDR.
+ IN[2] - Number of bytes in the data block
+ ReturnCode - One of the ERR_DE_... */
+/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */
+
+/* No Error / Success */
+#define CNXT_OK 0x000000
+
+/* Received unknown command */
+#define CXERR_UNK_CMD 0x000001
+
+/* First parameter in the command is invalid */
+#define CXERR_INVALID_PARAM1 0x000002
+
+/* Second parameter in the command is invalid */
+#define CXERR_INVALID_PARAM2 0x000003
+
+/* Device interface is not open/found */
+#define CXERR_DEV_NOT_FOUND 0x000004
+
+/* Requested function is not implemented/available */
+#define CXERR_NOTSUPPORTED 0x000005
+
+/* Invalid pointer is provided */
+#define CXERR_BADPTR 0x000006
+
+/* Unable to allocate memory */
+#define CXERR_NOMEM 0x000007
+
+/* Object/Link not found */
+#define CXERR_LINK 0x000008
+
+/* Device busy, command cannot be executed */
+#define CXERR_BUSY 0x000009
+
+/* File/device/handle is not open. */
+#define CXERR_NOT_OPEN 0x00000A
+
+/* Value is out of range */
+#define CXERR_OUTOFRANGE 0x00000B
+
+/* Buffer overflow */
+#define CXERR_OVERFLOW 0x00000C
+
+/* Version mismatch */
+#define CXERR_BADVER 0x00000D
+
+/* Operation timed out */
+#define CXERR_TIMEOUT 0x00000E
+
+/* Operation aborted */
+#define CXERR_ABORT 0x00000F
+
+/* Specified I2C device not found for read/write */
+#define CXERR_I2CDEV_NOTFOUND 0x000010
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_XFERERR 0x000011
+
+/* Chanel changing component not ready */
+#define CXERR_CHANNELNOTREADY 0x000012
+
+/* PPU (Presensation/Decoder) mail box is corrupted */
+#define CXERR_PPU_MB_CORRUPT 0x000013
+
+/* CPU (Capture/Encoder) mail box is corrupted */
+#define CXERR_CPU_MB_CORRUPT 0x000014
+
+/* APU (Audio) mail box is corrupted */
+#define CXERR_APU_MB_CORRUPT 0x000015
+
+/* Unable to open file for reading */
+#define CXERR_FILE_OPEN_READ 0x000016
+
+/* Unable to open file for writing */
+#define CXERR_FILE_OPEN_WRITE 0x000017
+
+/* Unable to find the I2C section specified */
+#define CXERR_I2C_BADSECTION 0x000018
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_DATALOW 0x000019
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_CLOCKLOW 0x00001A
+
+/* No Interrupt received from HW (for I2C access) */
+#define CXERR_NO_HW_I2C_INTR 0x00001B
+
+/* RPU is not ready to accept commands! */
+#define CXERR_RPU_NOT_READY 0x00001C
+
+/* RPU is not ready to accept commands! */
+#define CXERR_RPU_NO_ACK 0x00001D
+
+/* The are no buffers ready. Try again soon! */
+#define CXERR_NODATA_AGAIN 0x00001E
+
+/* The stream is stopping. Function not alllowed now! */
+#define CXERR_STOPPING_STATUS 0x00001F
+
+/* Trying to access hardware when the power is turned OFF */
+#define CXERR_DEVPOWER_OFF 0x000020
+
+#endif /* CX23418_H */
diff --git a/linux/drivers/media/video/cx23885/Kconfig b/linux/drivers/media/video/cx23885/Kconfig
index 1fd326fe4..7bf14c9a1 100644
--- a/linux/drivers/media/video/cx23885/Kconfig
+++ b/linux/drivers/media/video/cx23885/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_CX23885
tristate "Conexant cx23885 (2388x successor) support"
depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT
+ depends on HOTPLUG # due to FW_LOADER
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
@@ -8,14 +9,17 @@ config VIDEO_CX23885
select VIDEO_TVEEPROM
select VIDEO_IR
select VIDEOBUF_DVB
- select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE
+ select VIDEO_CX25840
+ select VIDEO_CX2341X
+ select DVB_DIB7000P if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_PLL if !DVB_FE_CUSTOMISE
- select TUNER_XC2028 if !DVB_FE_CUSTOMIZE
- select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
- select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
- select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
---help---
This is a video4linux driver for Conexant 23885 based
TV cards.
diff --git a/linux/drivers/media/video/cx23885/Makefile b/linux/drivers/media/video/cx23885/Makefile
index 32c90be50..29c23b44c 100644
--- a/linux/drivers/media/video/cx23885/Makefile
+++ b/linux/drivers/media/video/cx23885/Makefile
@@ -1,8 +1,9 @@
-cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c
new file mode 100644
index 000000000..1585db931
--- /dev/null
+++ b/linux/drivers/media/video/cx23885/cx23885-417.c
@@ -0,0 +1,1772 @@
+/*
+ *
+ * Support for a cx23417 mpeg encoder via cx23885 host port.
+ *
+ * (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * - CX23885/7/8 support
+ *
+ * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx2341x.h>
+
+#include "cx23885.h"
+#include "media/cx2341x.h"
+
+#define CX23885_FIRM_IMAGE_SIZE 376836
+#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+static unsigned int mpegbufs = 32;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 32;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+ "number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+
+#define dprintk(level, fmt, arg...)\
+ do { if (v4l_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg);\
+ } while (0)
+
+static struct cx23885_tvnorm cx23885_tvnorms[] = {
+ {
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
+ }, {
+ .name = "NTSC-JP",
+ .id = V4L2_STD_NTSC_M_JP,
+ }, {
+ .name = "PAL-BG",
+ .id = V4L2_STD_PAL_BG,
+ }, {
+ .name = "PAL-DK",
+ .id = V4L2_STD_PAL_DK,
+ }, {
+ .name = "PAL-I",
+ .id = V4L2_STD_PAL_I,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ }, {
+ .name = "PAL-N",
+ .id = V4L2_STD_PAL_N,
+ }, {
+ .name = "PAL-Nc",
+ .id = V4L2_STD_PAL_Nc,
+ }, {
+ .name = "PAL-60",
+ .id = V4L2_STD_PAL_60,
+ }, {
+ .name = "SECAM-L",
+ .id = V4L2_STD_SECAM_L,
+ }, {
+ .name = "SECAM-DK",
+ .id = V4L2_STD_SECAM_DK,
+ }
+};
+
+/* ------------------------------------------------------------------ */
+enum cx23885_capture_type {
+ CX23885_MPEG_CAPTURE,
+ CX23885_RAW_CAPTURE,
+ CX23885_RAW_PASSTHRU_CAPTURE
+};
+enum cx23885_capture_bits {
+ CX23885_RAW_BITS_NONE = 0x00,
+ CX23885_RAW_BITS_YUV_CAPTURE = 0x01,
+ CX23885_RAW_BITS_PCM_CAPTURE = 0x02,
+ CX23885_RAW_BITS_VBI_CAPTURE = 0x04,
+ CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+ CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10
+};
+enum cx23885_capture_end {
+ CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */
+ CX23885_END_NOW, /* stop immediately, no irq */
+};
+enum cx23885_framerate {
+ CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+ CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */
+};
+enum cx23885_stream_port {
+ CX23885_OUTPUT_PORT_MEMORY,
+ CX23885_OUTPUT_PORT_STREAMING,
+ CX23885_OUTPUT_PORT_SERIAL
+};
+enum cx23885_data_xfer_status {
+ CX23885_MORE_BUFFERS_FOLLOW,
+ CX23885_LAST_BUFFER,
+};
+enum cx23885_picture_mask {
+ CX23885_PICTURE_MASK_NONE,
+ CX23885_PICTURE_MASK_I_FRAMES,
+ CX23885_PICTURE_MASK_I_P_FRAMES = 0x3,
+ CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx23885_vbi_mode_bits {
+ CX23885_VBI_BITS_SLICED,
+ CX23885_VBI_BITS_RAW,
+};
+enum cx23885_vbi_insertion_bits {
+ CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+ CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx23885_dma_unit {
+ CX23885_DMA_BYTES,
+ CX23885_DMA_FRAMES,
+};
+enum cx23885_dma_transfer_status_bits {
+ CX23885_DMA_TRANSFER_BITS_DONE = 0x01,
+ CX23885_DMA_TRANSFER_BITS_ERROR = 0x04,
+ CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx23885_pause {
+ CX23885_PAUSE_ENCODING,
+ CX23885_RESUME_ENCODING,
+};
+enum cx23885_copyright {
+ CX23885_COPYRIGHT_OFF,
+ CX23885_COPYRIGHT_ON,
+};
+enum cx23885_notification_type {
+ CX23885_NOTIFICATION_REFRESH,
+};
+enum cx23885_notification_status {
+ CX23885_NOTIFICATION_OFF,
+ CX23885_NOTIFICATION_ON,
+};
+enum cx23885_notification_mailbox {
+ CX23885_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx23885_field1_lines {
+ CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */
+ CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */
+ CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx23885_field2_lines {
+ CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */
+ CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */
+ CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx23885_custom_data_type {
+ CX23885_CUSTOM_EXTENSION_USR_DATA,
+ CX23885_CUSTOM_PRIVATE_PACKET,
+};
+enum cx23885_mute {
+ CX23885_UNMUTE,
+ CX23885_MUTE,
+};
+enum cx23885_mute_video_mask {
+ CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00,
+ CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000,
+ CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx23885_mute_video_shift {
+ CX23885_MUTE_VIDEO_V_SHIFT = 8,
+ CX23885_MUTE_VIDEO_U_SHIFT = 16,
+ CX23885_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/**** Bit definitions for MC417_RWD and MC417_OEN registers ***
+ bits 31-16
++-----------+
+| Reserved |
++-----------+
+ bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+#define MC417_MIWR 0x8000
+#define MC417_MIRD 0x4000
+#define MC417_MICS 0x2000
+#define MC417_MIRDY 0x1000
+#define MC417_MIADDR 0x0F00
+#define MC417_MIDATA 0x00FF
+
+/* MIADDR* nibble definitions */
+#define MCI_MEMORY_DATA_BYTE0 0x000
+#define MCI_MEMORY_DATA_BYTE1 0x100
+#define MCI_MEMORY_DATA_BYTE2 0x200
+#define MCI_MEMORY_DATA_BYTE3 0x300
+#define MCI_MEMORY_ADDRESS_BYTE2 0x400
+#define MCI_MEMORY_ADDRESS_BYTE1 0x500
+#define MCI_MEMORY_ADDRESS_BYTE0 0x600
+#define MCI_REGISTER_DATA_BYTE0 0x800
+#define MCI_REGISTER_DATA_BYTE1 0x900
+#define MCI_REGISTER_DATA_BYTE2 0xA00
+#define MCI_REGISTER_DATA_BYTE3 0xB00
+#define MCI_REGISTER_ADDRESS_BYTE0 0xC00
+#define MCI_REGISTER_ADDRESS_BYTE1 0xD00
+#define MCI_REGISTER_MODE 0xE00
+
+/* Read and write modes */
+#define MCI_MODE_REGISTER_READ 0
+#define MCI_MODE_REGISTER_WRITE 1
+#define MCI_MODE_MEMORY_READ 0
+#define MCI_MODE_MEMORY_WRITE 0x40
+
+/*** Bit definitions for MC417_CTL register ****
+ bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0
++--------+-------------+--------+--------------+------------+
+|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
++--------+-------------+--------+--------------+------------+
+***/
+#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN 0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW 0x1
+#define MC417_SPD_CTL_MEDIUM 0x0
+#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3 0x3
+#define MC417_GPIO_SEL_GPIO2 0x2
+#define MC417_GPIO_SEL_GPIO1 0x1
+#define MC417_GPIO_SEL_GPIO0 0x0
+
+void cx23885_mc417_init(struct cx23885_dev *dev)
+{
+ u32 regval;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Configure MC417_CTL register to defaults. */
+ regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) |
+ MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) |
+ MC417_UART_GPIO_EN;
+ cx_write(MC417_CTL, regval);
+
+ /* Configure MC417_OEN to defaults. */
+ regval = MC417_MIRDY;
+ cx_write(MC417_OEN, regval);
+
+ /* Configure MC417_RWD to defaults. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS;
+ cx_write(MC417_RWD, regval);
+}
+
+static int mc417_wait_ready(struct cx23885_dev *dev)
+{
+ u32 mi_ready;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+ for (;;) {
+ mi_ready = cx_read(MC417_RWD) & MC417_MIRDY;
+ if (mi_ready != 0)
+ return 0;
+ if (time_after(jiffies, timeout))
+ return -1;
+ udelay(1);
+ }
+}
+
+static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
+{
+ u32 regval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
+ (value & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+
+ /* Transition CS/WR to effect write transaction across bus. */
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
+ ((value >> 8) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
+ ((value >> 16) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
+ ((value >> 24) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Indicate that this is a write. */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+ MCI_MODE_REGISTER_WRITE;
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ return mc417_wait_ready(dev);
+}
+
+static int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
+{
+ int retval;
+ u32 regval;
+ u32 tempval;
+ u32 dataval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+ ((address & 0x00FF));
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Indicate that this is a register read. */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+ MCI_MODE_REGISTER_READ;
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ retval = mc417_wait_ready(dev);
+
+ /* switch the DAT0-7 GPIO[10:3] to input mode */
+ cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+ /* Read data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+
+ /* Transition RD to effect read transaction across bus.
+ * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)?
+ * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its
+ * input only...)
+ */
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+
+ /* Collect byte */
+ tempval = cx_read(MC417_RWD);
+ dataval = tempval & 0x000000FF;
+
+ /* Bring CS and RD high. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 8);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 16);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 24);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ *value = dataval;
+
+ return retval;
+}
+
+int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value)
+{
+ u32 regval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
+ (value & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+
+ /* Transition CS/WR to effect write transaction across bus. */
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
+ ((value >> 8) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
+ ((value >> 16) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
+ ((value >> 24) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+ MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ return mc417_wait_ready(dev);
+}
+
+int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
+{
+ int retval;
+ u32 regval;
+ u32 tempval;
+ u32 dataval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write address byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+ MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ retval = mc417_wait_ready(dev);
+
+ /* switch the DAT0-7 GPIO[10:3] to input mode */
+ cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+ /* Read data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+
+ /* Transition RD to effect read transaction across bus. */
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+
+ /* Collect byte */
+ tempval = cx_read(MC417_RWD);
+ dataval = ((tempval & 0x000000FF) << 24);
+
+ /* Bring CS and RD high. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 16);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 8);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= (tempval & 0x000000FF);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ *value = dataval;
+
+ return retval;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+char *cmd_to_str(int cmd)
+{
+ switch (cmd) {
+ case CX2341X_ENC_PING_FW:
+ return "PING_FW";
+ case CX2341X_ENC_START_CAPTURE:
+ return "START_CAPTURE";
+ case CX2341X_ENC_STOP_CAPTURE:
+ return "STOP_CAPTURE";
+ case CX2341X_ENC_SET_AUDIO_ID:
+ return "SET_AUDIO_ID";
+ case CX2341X_ENC_SET_VIDEO_ID:
+ return "SET_VIDEO_ID";
+ case CX2341X_ENC_SET_PCR_ID:
+ return "SET_PCR_PID";
+ case CX2341X_ENC_SET_FRAME_RATE:
+ return "SET_FRAME_RATE";
+ case CX2341X_ENC_SET_FRAME_SIZE:
+ return "SET_FRAME_SIZE";
+ case CX2341X_ENC_SET_BIT_RATE:
+ return "SET_BIT_RATE";
+ case CX2341X_ENC_SET_GOP_PROPERTIES:
+ return "SET_GOP_PROPERTIES";
+ case CX2341X_ENC_SET_ASPECT_RATIO:
+ return "SET_ASPECT_RATIO";
+ case CX2341X_ENC_SET_DNR_FILTER_MODE:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_CORING_LEVELS:
+ return "SET_CORING_LEVELS";
+ case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+ return "SET_SPATIAL_FILTER_TYPE";
+ case CX2341X_ENC_SET_VBI_LINE:
+ return "SET_VBI_LINE";
+ case CX2341X_ENC_SET_STREAM_TYPE:
+ return "SET_STREAM_TYPE";
+ case CX2341X_ENC_SET_OUTPUT_PORT:
+ return "SET_OUTPUT_PORT";
+ case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+ return "SET_AUDIO_PROPERTIES";
+ case CX2341X_ENC_HALT_FW:
+ return "HALT_FW";
+ case CX2341X_ENC_GET_VERSION:
+ return "GET_VERSION";
+ case CX2341X_ENC_SET_GOP_CLOSURE:
+ return "SET_GOP_CLOSURE";
+ case CX2341X_ENC_GET_SEQ_END:
+ return "GET_SEQ_END";
+ case CX2341X_ENC_SET_PGM_INDEX_INFO:
+ return "SET_PGM_INDEX_INFO";
+ case CX2341X_ENC_SET_VBI_CONFIG:
+ return "SET_VBI_CONFIG";
+ case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+ return "SET_DMA_BLOCK_SIZE";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+ return "GET_PREV_DMA_INFO_MB_10";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+ return "GET_PREV_DMA_INFO_MB_9";
+ case CX2341X_ENC_SCHED_DMA_TO_HOST:
+ return "SCHED_DMA_TO_HOST";
+ case CX2341X_ENC_INITIALIZE_INPUT:
+ return "INITIALIZE_INPUT";
+ case CX2341X_ENC_SET_FRAME_DROP_RATE:
+ return "SET_FRAME_DROP_RATE";
+ case CX2341X_ENC_PAUSE_ENCODER:
+ return "PAUSE_ENCODER";
+ case CX2341X_ENC_REFRESH_INPUT:
+ return "REFRESH_INPUT";
+ case CX2341X_ENC_SET_COPYRIGHT:
+ return "SET_COPYRIGHT";
+ case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+ return "SET_EVENT_NOTIFICATION";
+ case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+ return "SET_NUM_VSYNC_LINES";
+ case CX2341X_ENC_SET_PLACEHOLDER:
+ return "SET_PLACEHOLDER";
+ case CX2341X_ENC_MUTE_VIDEO:
+ return "MUTE_VIDEO";
+ case CX2341X_ENC_MUTE_AUDIO:
+ return "MUTE_AUDIO";
+ case CX2341X_ENC_MISC:
+ return "MISC";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int cx23885_mbox_func(void *priv,
+ u32 command,
+ int in,
+ int out,
+ u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ struct cx23885_dev *dev = priv;
+ unsigned long timeout;
+ u32 value, flag, retval = 0;
+ int i;
+
+ dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+ cmd_to_str(command));
+
+ /* this may not be 100% safe if we can't read any memory location
+ without side effects */
+ mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+ if (value != 0x12345678) {
+ printk(KERN_ERR
+ "Firmware and/or mailbox pointer not initialized "
+ "or corrupted, signature = 0x%x, cmd = %s\n", value,
+ cmd_to_str(command));
+ return -1;
+ }
+
+ /* This read looks at 32 bits, but flag is only 8 bits.
+ * Seems we also bail if CMD or TIMEOUT bytes are set???
+ */
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (flag) {
+ printk(KERN_ERR "ERROR: Mailbox appears to be in use "
+ "(%x), cmd = %s\n", flag, cmd_to_str(command));
+ return -1;
+ }
+
+ flag |= 1; /* tell 'em we're working on it */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* write command + args + fill remaining with zeros */
+ /* command code */
+ mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+ mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+ IVTV_API_STD_TIMEOUT); /* timeout */
+ for (i = 0; i < in; i++) {
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+ dprintk(3, "API Input %d = %d\n", i, data[i]);
+ }
+ for (; i < CX2341X_MBOX_MAX_DATA; i++)
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+ flag |= 3; /* tell 'em we're done writing */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* wait for firmware to handle the API command */
+ timeout = jiffies + msecs_to_jiffies(10);
+ for (;;) {
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (0 != (flag & 4))
+ break;
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "ERROR: API Mailbox timeout\n");
+ return -1;
+ }
+ udelay(10);
+ }
+
+ /* read output values */
+ for (i = 0; i < out; i++) {
+ mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+ dprintk(3, "API Output %d = %d\n", i, data[i]);
+ }
+
+ mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+ dprintk(3, "API result = %d\n", retval);
+
+ flag = 0;
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx23885_api_cmd(struct cx23885_dev *dev,
+ u32 command,
+ u32 inputcnt,
+ u32 outputcnt,
+ ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i, err;
+
+ dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+ va_start(vargs, outputcnt);
+ for (i = 0; i < inputcnt; i++)
+ data[i] = va_arg(vargs, int);
+
+ err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data);
+ for (i = 0; i < outputcnt; i++) {
+ int *vptr = va_arg(vargs, int *);
+ *vptr = data[i];
+ }
+ va_end(vargs);
+
+ return err;
+}
+
+static int cx23885_find_mailbox(struct cx23885_dev *dev)
+{
+ u32 signature[4] = {
+ 0x12345678, 0x34567812, 0x56781234, 0x78123456
+ };
+ int signaturecnt = 0;
+ u32 value;
+ int i;
+
+ dprintk(2, "%s()\n", __func__);
+
+ for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) {
+ mc417_memory_read(dev, i, &value);
+ if (value == signature[signaturecnt])
+ signaturecnt++;
+ else
+ signaturecnt = 0;
+ if (4 == signaturecnt) {
+ dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+ return i+1;
+ }
+ }
+ printk(KERN_ERR "Mailbox signature values not found!\n");
+ return -1;
+}
+
+static int cx23885_load_firmware(struct cx23885_dev *dev)
+{
+ static const unsigned char magic[8] = {
+ 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+ };
+ const struct firmware *firmware;
+ int i, retval = 0;
+ u32 value = 0;
+ u32 gpio_output = 0;
+ u32 checksum = 0;
+ u32 *dataptr;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Save GPIO settings before reset of APU */
+ retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+ retval |= mc417_memory_read(dev, 0x900C, &value);
+
+ retval = mc417_register_write(dev,
+ IVTV_REG_VPU, 0xFFFFFFED);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_APU, 0);
+
+ if (retval != 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return -1;
+ }
+
+ retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME,
+ &dev->pci->dev);
+
+ if (retval != 0) {
+ printk(KERN_ERR
+ "ERROR: Hotplug firmware request failed (%s).\n",
+ CX2341X_FIRM_ENC_FILENAME);
+ printk(KERN_ERR "Please fix your hotplug setup, the board will "
+ "not work without firmware loaded!\n");
+ return -1;
+ }
+
+ if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
+ printk(KERN_ERR "ERROR: Firmware size mismatch "
+ "(have %zd, expected %d)\n",
+ firmware->size, CX23885_FIRM_IMAGE_SIZE);
+ release_firmware(firmware);
+ return -1;
+ }
+
+ if (0 != memcmp(firmware->data, magic, 8)) {
+ printk(KERN_ERR
+ "ERROR: Firmware magic mismatch, wrong file?\n");
+ release_firmware(firmware);
+ return -1;
+ }
+
+ /* transfer to the chip */
+ dprintk(2, "Loading firmware ...\n");
+ dataptr = (u32 *)firmware->data;
+ for (i = 0; i < (firmware->size >> 2); i++) {
+ value = *dataptr;
+ checksum += ~value;
+ if (mc417_memory_write(dev, i, value) != 0) {
+ printk(KERN_ERR "ERROR: Loading firmware failed!\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ dataptr++;
+ }
+
+ /* read back to verify with the checksum */
+ dprintk(1, "Verifying firmware ...\n");
+ for (i--; i >= 0; i--) {
+ if (mc417_memory_read(dev, i, &value) != 0) {
+ printk(KERN_ERR "ERROR: Reading firmware failed!\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ checksum -= ~value;
+ }
+ if (checksum) {
+ printk(KERN_ERR
+ "ERROR: Firmware load failed (checksum mismatch).\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ release_firmware(firmware);
+ dprintk(1, "Firmware upload successful.\n");
+
+ retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+ IVTV_CMD_HW_BLOCKS_RST);
+
+ /* Restore GPIO settings, make sure EIO14 is enabled as an output. */
+ dprintk(2, "%s: GPIO output EIO 0-15 was = 0x%x\n",
+ __func__, gpio_output);
+ /* Power-up seems to have GPIOs AFU. This was causing digital side
+ * to fail at power-up. Seems GPIOs should be set to 0x10ff0411 at
+ * power-up.
+ * gpio_output |= (1<<14);
+ */
+ /* Note: GPIO14 is specific to the HVR1800 here */
+ gpio_output = 0x10ff0411 | (1<<14);
+ retval |= mc417_register_write(dev, 0x9020, gpio_output | (1<<14));
+ dprintk(2, "%s: GPIO output EIO 0-15 now = 0x%x\n",
+ __func__, gpio_output);
+
+ dprintk(1, "%s: GPIO value EIO 0-15 was = 0x%x\n",
+ __func__, value);
+ value |= (1<<14);
+ dprintk(1, "%s: GPIO value EIO 0-15 now = 0x%x\n",
+ __func__, value);
+ retval |= mc417_register_write(dev, 0x900C, value);
+
+ retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
+ retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+ if (retval < 0)
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return 0;
+}
+
+void cx23885_417_check_encoder(struct cx23885_dev *dev)
+{
+ u32 status, seq;
+
+ status = seq = 0;
+ cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+ dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+static void cx23885_codec_settings(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ /* assign frame size */
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ dev->ts1.height, dev->ts1.width);
+
+ dev->mpeg_params.width = dev->ts1.width;
+ dev->mpeg_params.height = dev->ts1.height;
+ dev->mpeg_params.is_50hz =
+ (dev->encodernorm.id & V4L2_STD_625_50) != 0;
+
+ cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+
+ cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+ cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx23885_initialize_codec(struct cx23885_dev *dev)
+{
+ int version;
+ int retval;
+ u32 i, data[7];
+
+ dprintk(1, "%s()\n", __func__);
+
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+ if (retval < 0) {
+ dprintk(2, "%s() PING OK\n", __func__);
+ retval = cx23885_load_firmware(dev);
+ if (retval < 0) {
+ printk(KERN_ERR "%s() f/w load failed\n", __func__);
+ return retval;
+ }
+ dev->cx23417_mailbox = cx23885_find_mailbox(dev);
+ if (dev->cx23417_mailbox < 0) {
+ printk(KERN_ERR "%s() mailbox < 0, error\n",
+ __func__);
+ return -1;
+ }
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "ERROR: cx23417 firmware ping failed!\n");
+ return -1;
+ }
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+ &version);
+ if (retval < 0) {
+ printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+ "version failed!\n");
+ return -1;
+ }
+ dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+ msleep(200);
+ }
+
+ cx23885_codec_settings(dev);
+ msleep(60);
+
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+ CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115);
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+ CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0);
+
+ /* Setup to capture VBI */
+ data[0] = 0x0001BD00;
+ data[1] = 1; /* frames per interrupt */
+ data[2] = 4; /* total bufs */
+ data[3] = 0x91559155; /* start codes */
+ data[4] = 0x206080C0; /* stop codes */
+ data[5] = 6; /* lines */
+ data[6] = 64; /* BPL */
+
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+ data[2], data[3], data[4], data[5], data[6]);
+
+ for (i = 2; i <= 24; i++) {
+ int valid;
+
+ valid = ((i >= 19) && (i <= 21));
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+ valid, 0 , 0, 0);
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+ i | 0x80000000, valid, 0, 0, 0);
+ }
+
+ cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE);
+ msleep(60);
+
+ /* initialize the video input */
+ cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+ msleep(60);
+
+ /* Enable VIP style pixel invalidation so we work with scaled mode */
+ mc417_memory_write(dev, 2120, 0x00000080);
+
+ /* start capturing to the host interface */
+ cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+ CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
+ msleep(10);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx23885_fh *fh = q->priv_data;
+
+ fh->dev->ts1.ts_packet_size = mpeglinesize;
+ fh->dev->ts1.ts_packet_count = mpeglines;
+
+ *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+ *count = mpegbufs;
+
+ return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx23885_fh *fh = q->priv_data;
+ return cx23885_buf_prepare(q, &fh->dev->ts1,
+ (struct cx23885_buffer *)vb,
+ field);
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx23885_fh *fh = q->priv_data;
+ cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+}
+
+static struct videobuf_queue_ops cx23885_qops = {
+ .buf_setup = bb_buf_setup,
+ .buf_prepare = bb_buf_prepare,
+ .buf_queue = bb_buf_queue,
+ .buf_release = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int cx23885_queryctrl(struct cx23885_dev *dev,
+ struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ /* MPEG V4L2 controls */
+ if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+ return 0;
+}
+
+static int cx23885_querymenu(struct cx23885_dev *dev,
+ struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ cx23885_queryctrl(dev, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ cx2341x_ctrl_get_menu(qmenu->id));
+}
+
+int cx23885_do_ioctl(struct inode *inode, struct file *file, int radio,
+ struct cx23885_dev *dev, unsigned int cmd, void *arg,
+ v4l2_kioctl driver_ioctl)
+{
+ int err;
+
+ switch (cmd) {
+ /* ---------- tv norms ---------- */
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *e = arg;
+ unsigned int i;
+
+ i = e->index;
+ if (i >= ARRAY_SIZE(cx23885_tvnorms))
+ return -EINVAL;
+ err = v4l2_video_std_construct(e,
+ cx23885_tvnorms[e->index].id,
+ cx23885_tvnorms[e->index].name);
+ e->index = i;
+ if (err < 0)
+ return err;
+ return 0;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ *id = dev->encodernorm.id;
+ return 0;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
+ if (*id & cx23885_tvnorms[i].id)
+ break;
+ if (i == ARRAY_SIZE(cx23885_tvnorms))
+ return -EINVAL;
+ dev->encodernorm = cx23885_tvnorms[i];
+#if 0
+ /* Notify the video decoder and other i2c clients.
+ * This will likely need to be enabled for non NTSC
+ * formats.
+ */
+ cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_S_STD, id);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, id);
+#endif
+
+ return 0;
+ }
+
+ /* ------ input switching ---------- */
+ case VIDIOC_ENUMINPUT:
+ {
+ struct cx23885_input *input;
+ struct v4l2_input *i = arg;
+ unsigned int n;
+
+ n = i->index;
+ if (n >= 4)
+ return -EINVAL;
+ input = &cx23885_boards[dev->board].input[n];
+ if (input->type == 0)
+ return -EINVAL;
+ memset(i, 0, sizeof(*i));
+ i->index = n;
+ /* FIXME
+ * strcpy(i->name, input->name); */
+ strcpy(i->name, "unset");
+ if (input->type == CX23885_VMUX_TELEVISION ||
+ input->type == CX23885_VMUX_CABLE)
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
+ i->std |= cx23885_tvnorms[n].id;
+ return 0;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ unsigned int *i = arg;
+
+ *i = dev->input;
+ return 0;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ unsigned int *i = arg;
+
+ if (*i >= 4)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ /* --- tuner ioctls ------------------------------------------ */
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Television");
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
+
+ dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+
+ /* Update the A/V core */
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
+
+ return 0;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ memset(f, 0, sizeof(*f));
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->freq;
+
+ /* Assumption that tuner is always on bus 1 */
+ cx23885_call_i2c_clients(&dev->i2c_bus[1],
+ VIDIOC_G_FREQUENCY, f);
+
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
+ dev->tuner_type);
+ dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
+ f->tuner, f->type);
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (f->tuner != 0)
+ return -EINVAL;
+ if (f->type != V4L2_TUNER_ANALOG_TV)
+ return -EINVAL;
+ dev->freq = f->frequency;
+
+ /* Assumption that tuner is always on bus 1 */
+ cx23885_call_i2c_clients(&dev->i2c_bus[1],
+ VIDIOC_S_FREQUENCY, f);
+ return 0;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ /* Update the A/V core */
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, arg);
+ return 0;
+ }
+ default:
+ /* Convert V4L ioctl to V4L2 and call mpeg_do_ioctl
+ * (driver_ioctl) */
+ return v4l_compat_translate_ioctl(inode, file, cmd, arg,
+ driver_ioctl);
+ }
+
+ return 0;
+}
+
+static int mpeg_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx23885_tsport *tsport = &dev->ts1;
+
+ if (v4l_debug > 1)
+ v4l_print_ioctl(dev->name, cmd);
+
+ switch (cmd) {
+
+ /* --- capabilities ------------------------------------------ */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, dev->name);
+ strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+ cap->version = CX23885_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ 0;
+ if (UNSET != dev->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+
+ return 0;
+ }
+
+ /* --- capture ioctls ---------------------------------------- */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ int index;
+
+ index = f->index;
+ if (index != 0)
+ return -EINVAL;
+
+ memset(f, 0, sizeof(*f));
+ f->index = index;
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ return 0;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->ts1.width;
+ f->fmt.pix.height = dev->ts1.height;
+ f->fmt.pix.field = fh->mpegq.field;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ return 0;
+ }
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ return 0;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+ return 0;
+ }
+
+ /* --- streaming capture ------------------------------------- */
+ case VIDIOC_REQBUFS:
+ return videobuf_reqbufs(&fh->mpegq, arg);
+
+ case VIDIOC_QUERYBUF:
+ return videobuf_querybuf(&fh->mpegq, arg);
+
+ case VIDIOC_QBUF:
+ return videobuf_qbuf(&fh->mpegq, arg);
+
+ case VIDIOC_DQBUF:
+ return videobuf_dqbuf(&fh->mpegq, arg,
+ file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_STREAMON:
+ return videobuf_streamon(&fh->mpegq);
+
+ case VIDIOC_STREAMOFF:
+ return videobuf_streamoff(&fh->mpegq);
+
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *f = arg;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, cmd);
+ }
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *f = arg;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, cmd);
+ if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
+ err = cx2341x_update(dev, cx23885_mbox_func,
+ &dev->mpeg_params, &p);
+ dev->mpeg_params = p;
+ }
+ return err;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+ CX23885_RAW_BITS_NONE);
+ cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
+ mpeg_do_ioctl);
+ cx23885_initialize_codec(dev);
+
+ return 0;
+ }
+ case VIDIOC_LOG_STATUS:
+ {
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", dev->name);
+ printk(KERN_INFO
+ "%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
+ cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
+ NULL);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
+ NULL);
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
+ NULL);
+ cx2341x_log_status(&dev->mpeg_params, name);
+ printk(KERN_INFO
+ "%s/2: ============= END LOG STATUS =============\n",
+ dev->name);
+ return 0;
+ }
+ case VIDIOC_QUERYMENU:
+ return cx23885_querymenu(dev, arg);
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *c = arg;
+
+ return cx23885_queryctrl(dev, c);
+ }
+
+ default:
+ return cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
+ mpeg_do_ioctl);
+ }
+ return 0;
+}
+
+static int mpeg_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+}
+
+static int mpeg_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct cx23885_dev *h, *dev = NULL;
+ struct list_head *list;
+ struct cx23885_fh *fh;
+
+ dprintk(2, "%s()\n", __func__);
+
+ list_for_each(list, &cx23885_devlist) {
+ h = list_entry(list, struct cx23885_dev, devlist);
+ if (h->v4l_device->minor == minor) {
+ dev = h;
+ break;
+ }
+ }
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+ videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
+ &dev->pci->dev, &dev->ts1.slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx23885_buffer),
+ fh);
+
+ return 0;
+}
+
+static int mpeg_release(struct inode *inode, struct file *file)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* FIXME: Review this crap */
+ /* Shut device down on last close */
+ if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+ if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+ /* stop mpeg capture */
+ cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+ CX23885_RAW_BITS_NONE);
+
+ msleep(500);
+ cx23885_417_check_encoder(dev);
+
+ cx23885_cancel_buffers(&fh->dev->ts1);
+ }
+ }
+
+ if (fh->mpegq.streaming)
+ videobuf_streamoff(&fh->mpegq);
+ if (fh->mpegq.reading)
+ videobuf_read_stop(&fh->mpegq);
+
+ videobuf_mmap_free(&fh->mpegq);
+ file->private_data = NULL;
+ kfree(fh);
+
+ return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+ /* Start mpeg encoder on first read. */
+ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+ if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
+ if (cx23885_initialize_codec(dev) < 0)
+ return -EINVAL;
+ }
+ }
+
+ return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s\n", __func__);
+
+ return videobuf_poll_stream(file, &fh->mpegq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ return videobuf_mmap_mapper(&fh->mpegq, vma);
+}
+
+static struct file_operations mpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = mpeg_open,
+ .release = mpeg_release,
+ .read = mpeg_read,
+ .poll = mpeg_poll,
+ .mmap = mpeg_mmap,
+ .ioctl = mpeg_ioctl,
+ .llseek = no_llseek,
+};
+
+static struct video_device cx23885_mpeg_template = {
+ .name = "cx23885",
+ .type = VID_TYPE_CAPTURE |
+ VID_TYPE_TUNER |
+ VID_TYPE_SCALES |
+ VID_TYPE_MPEG_ENCODER,
+ .fops = &mpeg_fops,
+ .minor = -1,
+};
+
+void cx23885_417_unregister(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ if (dev->v4l_device) {
+ if (-1 != dev->v4l_device->minor)
+ video_unregister_device(dev->v4l_device);
+ else
+ video_device_release(dev->v4l_device);
+ dev->v4l_device = NULL;
+ }
+}
+
+static struct video_device *cx23885_video_dev_alloc(
+ struct cx23885_tsport *tsport,
+ struct pci_dev *pci,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+ struct cx23885_dev *dev = tsport->dev;
+
+ dprintk(1, "%s()\n", __func__);
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template;
+ vfd->minor = -1;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+ type, cx23885_boards[tsport->dev->board].name);
+ vfd->dev = &pci->dev;
+ vfd->release = video_device_release;
+ return vfd;
+}
+
+int cx23885_417_register(struct cx23885_dev *dev)
+{
+ /* FIXME: Port1 hardcoded here */
+ int err = -ENODEV;
+ struct cx23885_tsport *tsport = &dev->ts1;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER)
+ return err;
+
+ /* Set default TV standard */
+ dev->encodernorm = cx23885_tvnorms[0];
+
+ if (dev->encodernorm.id & V4L2_STD_525_60)
+ tsport->height = 480;
+ else
+ tsport->height = 576;
+
+ tsport->width = 720;
+ cx2341x_fill_defaults(&dev->mpeg_params);
+
+ dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+ /* Allocate and initialize V4L video device */
+ dev->v4l_device = cx23885_video_dev_alloc(tsport,
+ dev->pci, &cx23885_mpeg_template, "mpeg");
+ err = video_register_device(dev->v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (err < 0) {
+ printk(KERN_INFO "%s: can't register mpeg device\n", dev->name);
+ return err;
+ }
+
+ /* Initialize MC417 registers */
+ cx23885_mc417_init(dev);
+
+ printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
+ dev->name, dev->v4l_device->minor & 0x1f);
+
+ return 0;
+}
diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index 8a4d5143f..7171e344a 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -74,6 +74,7 @@ struct cx23885_board cx23885_boards[] = {
[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
.name = "Hauppauge WinTV-HVR1800",
.porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_ENCODER,
.portc = CX23885_MPEG_DVB,
.tuner_type = TUNER_PHILIPS_TDA8290,
.tuner_addr = 0x42, /* 0x84 >> 1 */
@@ -131,6 +132,25 @@ struct cx23885_board cx23885_boards[] = {
.name = "Hauppauge WinTV-HVR1500",
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_HAUPPAUGE_HVR1200] = {
+ .name = "Hauppauge WinTV-HVR1200",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1700] = {
+ .name = "Hauppauge WinTV-HVR1700",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1400] = {
+ .name = "Hauppauge WinTV-HVR1400",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = {
+ .name = "DViCO FusionHDTV7 Dual Express",
+#if 0
+ .portb = CX23885_MPEG_DVB,
+#endif
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -182,6 +202,26 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x7717,
.card = CX23885_BOARD_HAUPPAUGE_HVR1500,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x71d1,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1200,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x71d3,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1200,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8101,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1700,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8010,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1400,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xd618,
+ .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -221,6 +261,33 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
/* Make sure we support the board model */
switch (tv.model)
{
+ case 71009:
+ /* WinTV-HVR1200 (PCIe, Retail, full height)
+ * DVB-T and basic analog */
+ case 71359:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71439:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71449:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71939:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71949:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71959:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
+ case 71979:
+ /* WinTV-HVR1200 (PCIe, OEM, half height)
+ * DVB-T and basic analog */
+ case 71999:
+ /* WinTV-HVR1200 (PCIe, OEM, full height)
+ * DVB-T and basic analog */
case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
@@ -236,6 +303,15 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
case 79561: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
+ case 80019:
+ /* WinTV-HVR1400 (Express Card, Retail, IR,
+ * DVB-T and Basic analog */
+ case 81509:
+ /* WinTV-HVR1700 (PCIe, OEM, No IR, half height)
+ * DVB-T and MPEG2 HW Encoder */
+ case 81519:
+ /* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
+ * DVB-T and MPEG2 HW Encoder */
break;
default:
printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
@@ -265,7 +341,7 @@ int cx23885_tuner_callback(void *priv, int command, int arg)
}
else {
printk(KERN_ERR
- "%s(): Unknow command.\n", __FUNCTION__);
+ "%s(): Unknow command.\n", __func__);
return -EINVAL;
}
break;
@@ -307,6 +383,10 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
/* GPIO-15-18 cx23417 READY, CS, RD, WR */
/* GPIO-19 IR_RX */
+ /* CX23417 GPIO's */
+ /* EIO15 Zilog Reset */
+ /* EIO14 S5H1409/CX24227 Reset */
+
/* Force the TDA8295A into reset and back */
cx_set(GP0_IO, 0x00040004);
mdelay(20);
@@ -315,6 +395,50 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx_set(GP0_IO, 0x00040004);
mdelay(20);
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ /* GPIO-0 tda10048 demodulator reset */
+ /* GPIO-2 tda18271 tuner reset */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ /* GPIO-0 TDA10048 demodulator reset */
+ /* GPIO-2 TDA8295A Reset */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+
+ /* The following GPIO's are on the interna AVCore (cx25840) */
+ /* GPIO-19 IR_RX */
+ /* GPIO-20 IR_TX 416/DVBT Select */
+ /* GPIO-21 IIS DAT */
+ /* GPIO-22 IIS WCLK */
+ /* GPIO-23 IIS BCLK */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ /* GPIO-0 Dibcom7000p demodulator reset */
+ /* GPIO-2 xc3028L tuner reset */
+ /* GPIO-13 LED */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
}
}
@@ -325,6 +449,8 @@ int cx23885_ir_init(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
/* FIXME: Implement me */
break;
}
@@ -349,33 +475,69 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0x80);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1800:
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
}
switch (dev->board) {
+ case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ /* break omitted intentionally */
case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ /* Defaults for VID B - Analog encoder */
+ /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
+ ts1->gen_ctrl_val = 0x10e;
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+
+ /* APB_TSVALERR_POL (active low)*/
+ ts1->vld_misc_val = 0x2000;
+ ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc);
+
+ /* Defaults for VID C */
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- case CX23885_BOARD_HAUPPAUGE_HVR1800:
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
default:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
}
+ /* Certain boards support analog, or require the avcore to be
+ * loaded, ensure this happens.
+ */
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ request_module("cx25840");
+ break;
+ }
}
/* ------------------------------------------------------------------ */
diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c
index 9408d2cd2..95289bb54 100644
--- a/linux/drivers/media/video/cx23885/cx23885-core.c
+++ b/linux/drivers/media/video/cx23885/cx23885-core.c
@@ -191,25 +191,25 @@ static struct sram_channel cx23887_sram_channels[] = {
static int cx23885_risc_decode(u32 risc)
{
static char *instr[16] = {
- [ RISC_SYNC >> 28 ] = "sync",
- [ RISC_WRITE >> 28 ] = "write",
- [ RISC_WRITEC >> 28 ] = "writec",
- [ RISC_READ >> 28 ] = "read",
- [ RISC_READC >> 28 ] = "readc",
- [ RISC_JUMP >> 28 ] = "jump",
- [ RISC_SKIP >> 28 ] = "skip",
- [ RISC_WRITERM >> 28 ] = "writerm",
- [ RISC_WRITECM >> 28 ] = "writecm",
- [ RISC_WRITECR >> 28 ] = "writecr",
+ [RISC_SYNC >> 28] = "sync",
+ [RISC_WRITE >> 28] = "write",
+ [RISC_WRITEC >> 28] = "writec",
+ [RISC_READ >> 28] = "read",
+ [RISC_READC >> 28] = "readc",
+ [RISC_JUMP >> 28] = "jump",
+ [RISC_SKIP >> 28] = "skip",
+ [RISC_WRITERM >> 28] = "writerm",
+ [RISC_WRITECM >> 28] = "writecm",
+ [RISC_WRITECR >> 28] = "writecr",
};
static int incr[16] = {
- [ RISC_WRITE >> 28 ] = 3,
- [ RISC_JUMP >> 28 ] = 3,
- [ RISC_SKIP >> 28 ] = 1,
- [ RISC_SYNC >> 28 ] = 1,
- [ RISC_WRITERM >> 28 ] = 3,
- [ RISC_WRITECM >> 28 ] = 3,
- [ RISC_WRITECR >> 28 ] = 4,
+ [RISC_WRITE >> 28] = 3,
+ [RISC_JUMP >> 28] = 3,
+ [RISC_SKIP >> 28] = 1,
+ [RISC_SYNC >> 28] = 1,
+ [RISC_WRITERM >> 28] = 3,
+ [RISC_WRITECM >> 28] = 3,
+ [RISC_WRITECR >> 28] = 4,
};
static char *bits[] = {
"12", "13", "14", "resync",
@@ -261,7 +261,7 @@ void cx23885_wakeup(struct cx23885_tsport *port,
}
if (bc != 1)
printk("%s: %d buffers handled (should be 1)\n",
- __FUNCTION__, bc);
+ __func__, bc);
}
int cx23885_sram_channel_setup(struct cx23885_dev *dev,
@@ -273,7 +273,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
if (ch->cmds_start == 0)
{
- dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__,
+ dprintk(1, "%s() Erasing channel [%s]\n", __func__,
ch->name);
cx_write(ch->ptr1_reg, 0);
cx_write(ch->ptr2_reg, 0);
@@ -281,7 +281,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
cx_write(ch->cnt1_reg, 0);
return 0;
} else {
- dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__,
+ dprintk(1, "%s() Configuring channel [%s]\n", __func__,
ch->name);
}
@@ -298,7 +298,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
/* write CDT */
for (i = 0; i < lines; i++) {
- dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i,
+ dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i,
ch->fifo_start + bpl*i);
cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
cx_write(cdt + 16*i + 4, 0);
@@ -450,7 +450,7 @@ static void cx23885_shutdown(struct cx23885_dev *dev)
static void cx23885_reset(struct cx23885_dev *dev)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
cx23885_shutdown(dev);
@@ -483,7 +483,7 @@ static void cx23885_reset(struct cx23885_dev *dev)
static int cx23885_pci_quirks(struct cx23885_dev *dev)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
/* The cx23885 bridge has a weird bug which causes NMI to be asserted
* when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
@@ -514,11 +514,13 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
{
- dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno);
+ dprintk(1, "%s(portno=%d)\n", __func__, portno);
/* Transport bus init dma queue - Common settings */
port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */
port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */
+ port->vld_misc_val = 0x0;
+ port->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4);
spin_lock_init(&port->slock);
port->dev = dev;
@@ -545,7 +547,7 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
port->reg_ts_clk_en = VID_B_TS_CLK_EN;
port->reg_src_sel = VID_B_SRC_SEL;
port->reg_ts_int_msk = VID_B_INT_MSK;
- port->reg_ts_int_stat = VID_B_INT_STAT;
+ port->reg_ts_int_stat = VID_B_INT_STAT;
port->sram_chno = SRAM_CH03; /* VID_B */
port->pci_irqmask = 0x02; /* VID_B bit1 */
break;
@@ -605,14 +607,14 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
break;
default:
printk(KERN_ERR "%s() New hardware revision found 0x%x\n",
- __FUNCTION__, dev->hwrevision);
+ __func__, dev->hwrevision);
}
if (dev->hwrevision)
printk(KERN_INFO "%s() Hardware revision = 0x%02x\n",
- __FUNCTION__, dev->hwrevision);
+ __func__, dev->hwrevision);
else
printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n",
- __FUNCTION__, dev->hwrevision);
+ __func__, dev->hwrevision);
}
static int cx23885_dev_setup(struct cx23885_dev *dev)
@@ -645,7 +647,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
BUG();
dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
- __FUNCTION__, dev->bridge);
+ __func__, dev->bridge);
/* board config */
dev->board = UNSET;
@@ -698,10 +700,12 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
- if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) ||
+ (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER))
cx23885_init_tsport(dev, &dev->ts1, 1);
- if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+ if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) ||
+ (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
cx23885_init_tsport(dev, &dev->ts2, 2);
if (get_resources(dev) < 0) {
@@ -735,9 +739,9 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dev->radio_addr = cx23885_boards[dev->board].radio_addr;
dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n",
- __FUNCTION__, dev->tuner_type, dev->tuner_addr);
+ __func__, dev->tuner_type, dev->tuner_addr);
dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
- __FUNCTION__, dev->radio_type, dev->radio_addr);
+ __func__, dev->radio_type, dev->radio_addr);
/* init hardware */
cx23885_reset(dev);
@@ -745,28 +749,43 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
cx23885_i2c_register(&dev->i2c_bus[0]);
cx23885_i2c_register(&dev->i2c_bus[1]);
cx23885_i2c_register(&dev->i2c_bus[2]);
- cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
cx23885_card_setup(dev);
+ cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
cx23885_ir_init(dev);
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
if (cx23885_video_register(dev) < 0) {
printk(KERN_ERR "%s() Failed to register analog "
- "video adapters on VID_A\n", __FUNCTION__);
+ "video adapters on VID_A\n", __func__);
}
}
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
if (cx23885_dvb_register(&dev->ts1) < 0) {
printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
- __FUNCTION__);
+ __func__);
+ }
+ } else
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
+ if (cx23885_417_register(dev) < 0) {
+ printk(KERN_ERR
+ "%s() Failed to register 417 on VID_B\n",
+ __func__);
}
}
if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
if (cx23885_dvb_register(&dev->ts2) < 0) {
- printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
- __FUNCTION__);
+ printk(KERN_ERR
+ "%s() Failed to register dvb on VID_C\n",
+ __func__);
+ }
+ } else
+ if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) {
+ if (cx23885_417_register(dev) < 0) {
+ printk(KERN_ERR
+ "%s() Failed to register 417 on VID_C\n",
+ __func__);
}
}
@@ -786,12 +805,18 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
cx23885_video_unregister(dev);
- if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
cx23885_dvb_unregister(&dev->ts1);
- if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ cx23885_417_unregister(dev);
+
+ if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
cx23885_dvb_unregister(&dev->ts2);
+ if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
+ cx23885_417_unregister(dev);
+
cx23885_i2c_unregister(&dev->i2c_bus[2]);
cx23885_i2c_unregister(&dev->i2c_bus[1]);
cx23885_i2c_unregister(&dev->i2c_bus[0]);
@@ -799,7 +824,7 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
iounmap(dev->lmmio);
}
-static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist,
+static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines)
@@ -859,7 +884,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int padding, unsigned int lines)
{
u32 instructions, fields;
- u32 *rp;
+ __le32 *rp;
int rc;
fields = 0;
@@ -900,7 +925,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
unsigned int lines)
{
u32 instructions;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -927,7 +952,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value)
{
- u32 *rp;
+ __le32 *rp;
int rc;
if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
@@ -961,50 +986,50 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
- dprintk(1, "%s() Register Dump\n", __FUNCTION__);
- dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() Register Dump\n", __func__);
+ dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__,
cx_read(DEV_CNTRL2));
- dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__,
cx_read(PCI_INT_MSK));
- dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__,
cx_read(AUDIO_INT_INT_MSK));
- dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__,
cx_read(AUD_INT_DMA_CTL));
- dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __func__,
cx_read(AUDIO_EXT_INT_MSK));
- dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __func__,
cx_read(AUD_EXT_DMA_CTL));
- dprintk(1, "%s() PAD_CTRL 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() PAD_CTRL 0x%08X\n", __func__,
cx_read(PAD_CTRL));
- dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __func__,
cx_read(ALT_PIN_OUT_SEL));
- dprintk(1, "%s() GPIO2 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() GPIO2 0x%08X\n", __func__,
cx_read(GPIO2));
- dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __func__,
port->reg_gpcnt, cx_read(port->reg_gpcnt));
- dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __func__,
port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
- dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__,
port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
- dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__,
port->reg_src_sel, cx_read(port->reg_src_sel));
- dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__,
port->reg_lngth, cx_read(port->reg_lngth));
- dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__,
port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
- dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __func__,
port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
- dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __func__,
port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
- dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __func__,
port->reg_sop_status, cx_read(port->reg_sop_status));
- dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__,
port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
- dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __func__,
port->reg_vld_misc, cx_read(port->reg_vld_misc));
- dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __func__,
port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
- dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__,
port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
}
@@ -1013,8 +1038,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
struct cx23885_buffer *buf)
{
struct cx23885_dev *dev = port->dev;
+ u32 reg;
- dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__,
+ dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
buf->vb.width, buf->vb.height, buf->vb.field);
/* setup fifo + format */
@@ -1032,21 +1058,24 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) {
printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n",
- __FUNCTION__,
+ __func__,
cx23885_boards[dev->board].portb,
cx23885_boards[dev->board].portc );
return -EINVAL;
}
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ cx23885_av_clk(dev, 0);
+
udelay(100);
/* If the port supports SRC SELECT, configure it */
if(port->reg_src_sel)
cx_write(port->reg_src_sel, port->src_sel_val);
- cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4);
+ cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val);
cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
- cx_write(port->reg_vld_misc, 0x00);
+ cx_write(port->reg_vld_misc, port->vld_misc_val);
cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
udelay(100);
@@ -1055,11 +1084,26 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
cx_write(port->reg_gpcnt_ctl, 3);
q->count = 1;
+ if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) {
+
+ reg = cx_read(PAD_CTRL);
+ reg = reg & ~0x1; /* Clear TS1_OE */
+
+ /* FIXME, bit 2 writing here is questionable */
+ /* set TS1_SOP_OE and TS1_OE_HI */
+ reg = reg | 0xa;
+ cx_write(PAD_CTRL, reg);
+
+ /* FIXME and these two registers should be documented. */
+ cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011);
+ cx_write(ALT_PIN_OUT_SEL, 0x10100045);
+ }
+
switch(dev->bridge) {
case CX23885_BRIDGE_885:
case CX23885_BRIDGE_887:
/* enable irqs */
- dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ );
+ dprintk(1, "%s() enabling TS int's and DMA\n", __func__ );
cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_set(port->reg_dma_ctl, port->dma_ctl_val);
cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
@@ -1070,6 +1114,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ cx23885_av_clk(dev, 1);
+
if (debug > 4)
cx23885_tsport_reg_dump(port);
@@ -1079,12 +1126,38 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
static int cx23885_stop_dma(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
- dprintk(1, "%s()\n", __FUNCTION__);
+ u32 reg;
+
+ dprintk(1, "%s()\n", __func__);
/* Stop interrupts and DMA */
cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+ if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) {
+
+ reg = cx_read(PAD_CTRL);
+
+ /* Set TS1_OE */
+ reg = reg | 0x1;
+
+ /* clear TS1_SOP_OE and TS1_OE_HI */
+ reg = reg & ~0xa;
+ cx_write(PAD_CTRL, reg);
+#if 0
+ /*
+ * cx_write(CLK_DELAY, cx_read(CLK_DELAY) & ~0x80000011); ????
+ * cx_write(ALT_PIN_OUT_SEL, 0x10100045); ?? need to undo this?
+ */
+#endif
+ cx_write(port->reg_src_sel, 0);
+ cx_write(port->reg_gen_ctrl, 8);
+
+ }
+
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ cx23885_av_clk(dev, 0);
+
return 0;
}
@@ -1094,13 +1167,13 @@ int cx23885_restart_queue(struct cx23885_tsport *port,
struct cx23885_dev *dev = port->dev;
struct cx23885_buffer *buf;
- dprintk(5, "%s()\n", __FUNCTION__);
+ dprintk(5, "%s()\n", __func__);
if (list_empty(&q->active))
{
struct cx23885_buffer *prev;
prev = NULL;
- dprintk(5, "%s() queue is empty\n", __FUNCTION__);
+ dprintk(5, "%s() queue is empty\n", __func__);
for (;;) {
if (list_empty(&q->queued))
@@ -1155,7 +1228,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
int size = port->ts_packet_size * port->ts_packet_count;
int rc;
- dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+ dprintk(1, "%s: %p\n", __func__, buf);
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
@@ -1198,7 +1271,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
buf->count = cx88q->count++;
mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
dprintk(1, "[%p/%d] %s - first active\n",
- buf, buf->vb.i, __FUNCTION__);
+ buf, buf->vb.i, __func__);
} else {
dprintk( 1, "queue is not empty - append to active\n" );
prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
@@ -1209,7 +1282,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
dprintk( 1, "[%p/%d] %s - append to active\n",
- buf, buf->vb.i, __FUNCTION__);
+ buf, buf->vb.i, __func__);
}
}
@@ -1240,7 +1313,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
spin_unlock_irqrestore(&port->slock, flags);
}
-#if 0
void cx23885_cancel_buffers(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
@@ -1251,14 +1323,13 @@ void cx23885_cancel_buffers(struct cx23885_tsport *port)
cx23885_stop_dma(port);
do_cancel_buffers(port, "cancel", 0);
}
-#endif /* 0 */
static void cx23885_timeout(unsigned long data)
{
struct cx23885_tsport *port = (struct cx23885_tsport *)data;
struct cx23885_dev *dev = port->dev;
- dprintk(1, "%s()\n",__FUNCTION__);
+ dprintk(1, "%s()\n",__func__);
if (debug > 5)
cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
@@ -1267,16 +1338,77 @@ static void cx23885_timeout(unsigned long data)
do_cancel_buffers(port, "timeout", 1);
}
+int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
+{
+ /* FIXME: port1 assumption here. */
+ struct cx23885_tsport *port = &dev->ts1;
+ int count = 0;
+ int handled = 0;
+
+ if (status == 0)
+ return handled;
+
+ count = cx_read(port->reg_gpcnt);
+ dprintk(7, "status: 0x%08x mask: 0x%08x count: 0x%x\n",
+ status, cx_read(port->reg_ts_int_msk), count);
+
+ if ((status & VID_B_MSK_BAD_PKT) ||
+ (status & VID_B_MSK_OPC_ERR) ||
+ (status & VID_B_MSK_VBI_OPC_ERR) ||
+ (status & VID_B_MSK_SYNC) ||
+ (status & VID_B_MSK_VBI_SYNC) ||
+ (status & VID_B_MSK_OF) ||
+ (status & VID_B_MSK_VBI_OF)) {
+ printk(KERN_ERR "%s: V4L mpeg risc op code error, status "
+ "= 0x%x\n", dev->name, status);
+ if (status & VID_B_MSK_BAD_PKT)
+ dprintk(1, " VID_B_MSK_BAD_PKT\n");
+ if (status & VID_B_MSK_OPC_ERR)
+ dprintk(1, " VID_B_MSK_OPC_ERR\n");
+ if (status & VID_B_MSK_VBI_OPC_ERR)
+ dprintk(1, " VID_B_MSK_VBI_OPC_ERR\n");
+ if (status & VID_B_MSK_SYNC)
+ dprintk(1, " VID_B_MSK_SYNC\n");
+ if (status & VID_B_MSK_VBI_SYNC)
+ dprintk(1, " VID_B_MSK_VBI_SYNC\n");
+ if (status & VID_B_MSK_OF)
+ dprintk(1, " VID_B_MSK_OF\n");
+ if (status & VID_B_MSK_VBI_OF)
+ dprintk(1, " VID_B_MSK_VBI_OF\n");
+
+ cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+ cx23885_sram_channel_dump(dev,
+ &dev->sram_channels[port->sram_chno]);
+ cx23885_417_check_encoder(dev);
+ } else if (status & VID_B_MSK_RISCI1) {
+ dprintk(7, " VID_B_MSK_RISCI1\n");
+ spin_lock(&port->slock);
+ cx23885_wakeup(port, &port->mpegq, count);
+ spin_unlock(&port->slock);
+ } else if (status & VID_B_MSK_RISCI2) {
+ dprintk(7, " VID_B_MSK_RISCI2\n");
+ spin_lock(&port->slock);
+ cx23885_restart_queue(port, &port->mpegq);
+ spin_unlock(&port->slock);
+ }
+ if (status) {
+ cx_write(port->reg_ts_int_stat, status);
+ handled = 1;
+ }
+
+ return handled;
+}
+
static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
{
struct cx23885_dev *dev = port->dev;
int handled = 0;
u32 count;
- if ( (status & VID_BC_MSK_OPC_ERR) ||
- (status & VID_BC_MSK_BAD_PKT) ||
- (status & VID_BC_MSK_SYNC) ||
- (status & VID_BC_MSK_OF))
+ if ((status & VID_BC_MSK_OPC_ERR) ||
+ (status & VID_BC_MSK_BAD_PKT) ||
+ (status & VID_BC_MSK_SYNC) ||
+ (status & VID_BC_MSK_OF))
{
if (status & VID_BC_MSK_OPC_ERR)
dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR);
@@ -1290,7 +1422,8 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
- cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+ cx23885_sram_channel_dump(dev,
+ &dev->sram_channels[port->sram_chno]);
} else if (status & VID_BC_MSK_RISCI1) {
@@ -1395,11 +1528,17 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
if (ts1_status) {
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
handled += cx23885_irq_ts(ts1, ts1_status);
+ else
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ handled += cx23885_irq_417(dev, ts1_status);
}
if (ts2_status) {
if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
handled += cx23885_irq_ts(ts2, ts2_status);
+ else
+ if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
+ handled += cx23885_irq_417(dev, ts2_status);
}
if (vida_status)
@@ -1439,7 +1578,8 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
- dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0));
+ dev->pci_lat,
+ (unsigned long long)pci_resource_start(pci_dev, 0));
pci_set_master(pci_dev);
if (!pci_dma_supported(pci_dev, 0xffffffff)) {
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index 382558866..2c1ae4d38 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -37,10 +37,11 @@
#include "tda18271.h"
#include "lgdt330x.h"
#include "xc5000.h"
-#include "dvb-pll.h"
+#include "tda10048.h"
#include "tuner-xc2028.h"
-#include "tuner-xc2028-types.h"
#include "tuner-simple.h"
+#include "dib7000p.h"
+#include "dibx000_common.h"
static unsigned int debug;
@@ -55,6 +56,8 @@ static unsigned int alt_tuner;
module_param(alt_tuner, int, 0644);
MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
/* ------------------------------------------------------------------ */
static int dvb_buf_setup(struct videobuf_queue *q,
@@ -106,6 +109,13 @@ static struct s5h1409_config hauppauge_generic_config = {
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
};
+static struct tda10048_config hauppauge_hvr1200_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_SERIAL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON
+};
+
static struct s5h1409_config hauppauge_ezqam_config = {
.demod_address = 0x32 >> 1,
.output_mode = S5H1409_SERIAL_OUTPUT,
@@ -155,12 +165,28 @@ static struct s5h1409_config hauppauge_hvr1500q_config = {
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
};
+static struct s5h1409_config dvico_s5h1409_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
.i2c_address = 0x61,
.if_khz = 5380,
.tuner_callback = cx23885_tuner_callback
};
+static struct xc5000_config dvico_xc5000_tunerconfig = {
+ .i2c_address = 0x64,
+ .if_khz = 5380,
+ .tuner_callback = cx23885_tuner_callback
+};
+
static struct tda829x_config tda829x_no_probe = {
.probe_tuner = TDA829X_DONT_PROBE,
};
@@ -177,6 +203,96 @@ static struct tda18271_config hauppauge_tda18271_config = {
.gate = TDA18271_GATE_ANALOG,
};
+static struct tda18271_config hauppauge_hvr1200_tuner_config = {
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static struct dibx000_agc_config xc3028_agc_config = {
+ BAND_VHF | BAND_UHF, /* band_caps */
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
+ * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0,
+ * P_agc_nb_est=2, P_agc_write=0
+ */
+ (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
+ (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
+
+ 712, /* inv_gain */
+ 21, /* time_stabiliz */
+
+ 0, /* alpha_level */
+ 118, /* thlock */
+
+ 0, /* wbd_inv */
+ 2867, /* wbd_ref */
+ 0, /* wbd_sel */
+ 2, /* wbd_alpha */
+
+ 0, /* agc1_max */
+ 0, /* agc1_min */
+ 39718, /* agc2_max */
+ 9930, /* agc2_min */
+ 0, /* agc1_pt1 */
+ 0, /* agc1_pt2 */
+ 0, /* agc1_pt3 */
+ 0, /* agc1_slope1 */
+ 0, /* agc1_slope2 */
+ 0, /* agc2_pt1 */
+ 128, /* agc2_pt2 */
+ 29, /* agc2_slope1 */
+ 29, /* agc2_slope2 */
+
+ 17, /* alpha_mant */
+ 27, /* alpha_exp */
+ 23, /* beta_mant */
+ 51, /* beta_exp */
+
+ 1, /* perform_agc_softsplit */
+};
+
+/* PLL Configuration for COFDM BW_MHz = 8.000000
+ * With external clock = 30.000000 */
+static struct dibx000_bandwidth_config xc3028_bw_config = {
+ 60000, /* internal */
+ 30000, /* sampling */
+ 1, /* pll_cfg: prediv */
+ 8, /* pll_cfg: ratio */
+ 3, /* pll_cfg: range */
+ 1, /* pll_cfg: reset */
+ 0, /* pll_cfg: bypass */
+ 0, /* misc: refdiv */
+ 0, /* misc: bypclk_div */
+ 1, /* misc: IO_CLK_en_core */
+ 1, /* misc: ADClkSrc */
+ 0, /* misc: modulo */
+ (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+ (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
+ 20452225, /* timf */
+ 30000000 /* xtal_hz */
+};
+
+static struct dib7000p_config hauppauge_hvr1400_dib7000_config = {
+ .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 0,
+ .update_lna = NULL,
+
+ .agc_config_count = 1,
+ .agc = &xc3028_agc_config,
+ .bw = &xc3028_bw_config,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .pwm_freq_div = 0,
+ .agc_control = NULL,
+ .spur_protect = 0,
+
+ .output_mode = OUTMODE_MPEG2_SERIAL,
+};
+
static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
{
struct cx23885_tsport *port = ptr;
@@ -186,7 +302,7 @@ static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
case XC2028_TUNER_RESET:
/* Send the tuner in then out of reset */
/* GPIO-2 xc3028 tuner */
- dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+ dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
cx_set(GP0_IO, 0x00040000);
cx_clear(GP0_IO, 0x00000004);
@@ -196,10 +312,10 @@ static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
msleep(5);
break;
case XC2028_RESET_CLK:
- dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+ dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
break;
default:
- dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
+ dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
command, arg);
return -EINVAL;
}
@@ -285,12 +401,10 @@ static int dvb_register(struct cx23885_tsport *port)
port->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1500q_config,
&dev->i2c_bus[0].i2c_adap);
- if (port->dvb.frontend != NULL) {
- hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
+ if (port->dvb.frontend != NULL)
dvb_attach(xc5000_attach, port->dvb.frontend,
&i2c_bus->i2c_adap,
- &hauppauge_hvr1500q_tunerconfig);
- }
+ &hauppauge_hvr1500q_tunerconfig, i2c_bus);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500:
i2c_bus = &dev->i2c_bus[1];
@@ -307,7 +421,47 @@ static int dvb_register(struct cx23885_tsport *port)
static struct xc2028_ctrl ctl = {
.fname = "xc3028-v27.fw",
.max_len = 64,
- .scode_table = OREN538,
+ .scode_table = XC3028_FE_OREN538,
+ };
+
+ fe = dvb_attach(xc2028_attach,
+ port->dvb.frontend, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(tda10048_attach,
+ &hauppauge_hvr1200_config,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, port->dvb.frontend,
+ &dev->i2c_bus[1].i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, port->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_hvr1200_tuner_config);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(dib7000p_attach,
+ &i2c_bus->i2c_adap,
+ 0x12, &hauppauge_hvr1400_dib7000_config);
+ if (port->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_bus[1].i2c_adap,
+ .i2c_addr = 0x64,
+ .callback = cx23885_hvr1500_xc3028_callback,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = "xc3028L-v36.fw",
+ .max_len = 64,
+ .demod = 5000,
+ .d2633 = 1
};
fe = dvb_attach(xc2028_attach,
@@ -316,6 +470,17 @@ static int dvb_register(struct cx23885_tsport *port)
fe->ops.tuner_ops.set_config(fe, &ctl);
}
break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
+ i2c_bus = &dev->i2c_bus[port->nr - 1];
+
+ port->dvb.frontend = dvb_attach(s5h1409_attach,
+ &dvico_s5h1409_config,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL)
+ dvb_attach(xc5000_attach, port->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &dvico_xc5000_tunerconfig, i2c_bus);
+ break;
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->name);
@@ -334,7 +499,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* register everything */
return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
- &dev->pci->dev);
+ &dev->pci->dev, adapter_nr);
}
int cx23885_dvb_register(struct cx23885_tsport *port)
@@ -342,7 +507,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
struct cx23885_dev *dev = port->dev;
int err;
- dprintk(1, "%s\n", __FUNCTION__);
+ dprintk(1, "%s\n", __func__);
dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
dev->board,
dev->name,
@@ -358,7 +523,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
sizeof(struct cx23885_buffer), port);
err = dvb_register(port);
if (err != 0)
- printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err);
+ printk("%s() dvb_register failed err = %d\n", __func__, err);
return err;
}
diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c
index ab83c88a9..ba8e27ca9 100644
--- a/linux/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c
@@ -88,10 +88,10 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
int retval, cnt;
if (joined_rlen)
- dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__,
+ dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__,
msg->len, joined_rlen);
else
- dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+ dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
/* Deal with i2c probe functions with zero payload */
if (msg->len == 0) {
@@ -102,7 +102,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
if (!i2c_slave_did_ack(i2c_adap))
return -EIO;
- dprintk(1, "%s() returns 0\n", __FUNCTION__);
+ dprintk(1, "%s() returns 0\n", __func__);
return 0;
}
@@ -177,7 +177,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
if (i2c_debug && !joined)
- dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+ dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
/* Deal with i2c probe functions with zero payload */
if (msg->len == 0) {
@@ -189,7 +189,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
return -EIO;
- dprintk(1, "%s() returns 0\n", __FUNCTION__);
+ dprintk(1, "%s() returns 0\n", __func__);
return 0;
}
@@ -239,11 +239,11 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
struct cx23885_dev *dev = bus->dev;
int i, retval = 0;
- dprintk(1, "%s(num = %d)\n", __FUNCTION__, num);
+ dprintk(1, "%s(num = %d)\n", __func__, num);
for (i = 0 ; i < num; i++) {
dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
- __FUNCTION__, num, msgs[i].addr, msgs[i].len);
+ __func__, num, msgs[i].addr, msgs[i].len);
if (msgs[i].flags & I2C_M_RD) {
/* read */
retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
@@ -374,6 +374,8 @@ static struct i2c_client cx23885_i2c_client_template = {
};
static char *i2c_devs[128] = {
+ [0x10 >> 1] = "tda10048",
+ [0x12 >> 1] = "dib7000pc",
[ 0x1c >> 1 ] = "lgdt3303",
[ 0x86 >> 1 ] = "tda9887",
[ 0x32 >> 1 ] = "cx24227",
@@ -381,7 +383,8 @@ static char *i2c_devs[128] = {
[ 0x84 >> 1 ] = "tda8295",
[ 0xa0 >> 1 ] = "eeprom",
[ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
- [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000",
+ [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028",
+ [0xc8 >> 1] = "tuner/xc3028L",
};
static void do_i2c_scan(char *name, struct i2c_client *c)
@@ -404,7 +407,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
{
struct cx23885_dev *dev = bus->dev;
- dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr);
+ dprintk(1, "%s(bus = %d)\n", __func__, bus->nr);
memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template,
sizeof(bus->i2c_adap));
@@ -441,6 +444,29 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus)
return 0;
}
+void cx23885_av_clk(struct cx23885_dev *dev, int enable)
+{
+ /* write 0 to bus 2 addr 0x144 via i2x_xfer() */
+ char buffer[3];
+ struct i2c_msg msg;
+ dprintk(1, "%s(enabled = %d)\n", __func__, enable);
+
+ /* Register 0x144 */
+ buffer[0] = 0x01;
+ buffer[1] = 0x44;
+ if (enable == 1)
+ buffer[2] = 0x05;
+ else
+ buffer[2] = 0x00;
+
+ msg.addr = 0x44;
+ msg.flags = I2C_M_TEN;
+ msg.len = 3;
+ msg.buf = buffer;
+
+ i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
+}
+
/* ----------------------------------------------------------------------- */
/*
diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c
index 702d76493..fdbcd53ab 100644
--- a/linux/drivers/media/video/cx23885/cx23885-video.c
+++ b/linux/drivers/media/video/cx23885/cx23885-video.c
@@ -188,7 +188,7 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
if (formats[i].fourcc == fourcc)
return formats+i;
- printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc);
+ printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc);
return NULL;
}
@@ -342,13 +342,13 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
}
if (bc != 1)
printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
- __FUNCTION__, bc);
+ __func__, bc);
}
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
{
dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
- __FUNCTION__,
+ __func__,
(unsigned int)norm,
v4l2_norm_to_name(norm));
@@ -369,7 +369,7 @@ struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
char *type)
{
struct video_device *vfd;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
vfd = video_device_alloc();
if (NULL == vfd)
@@ -410,7 +410,7 @@ EXPORT_SYMBOL(cx23885_ctrl_query);
static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
unsigned int bit)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
if (fh->resources & bit)
/* have it already allocated */
return 1;
@@ -444,7 +444,7 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
unsigned int bits)
{
BUG_ON((fh->resources & bits) != bits);
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
mutex_lock(&dev->lock);
fh->resources &= ~bits;
@@ -459,7 +459,7 @@ int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
memset(&route, 0, sizeof(route));
dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
- __FUNCTION__,
+ __func__,
input, INPUT(input)->vmux,
INPUT(input)->gpio0, INPUT(input)->gpio1,
INPUT(input)->gpio2, INPUT(input)->gpio3);
@@ -484,7 +484,7 @@ EXPORT_SYMBOL(cx23885_video_mux);
int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
unsigned int height, enum v4l2_field field)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
return 0;
}
@@ -492,7 +492,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
struct cx23885_dmaqueue *q,
struct cx23885_buffer *buf)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
/* setup fifo + format */
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
@@ -518,7 +518,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
#ifdef CONFIG_PM
static int cx23885_stop_video_dma(struct cx23885_dev *dev)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
/* stop dma */
cx_clear(VID_A_DMA_CTL, 0x11);
@@ -536,7 +536,7 @@ static int cx23885_restart_video_queue(struct cx23885_dev *dev,
{
struct cx23885_buffer *buf, *prev;
struct list_head *item;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
if (!list_empty(&q->active)) {
buf = list_entry(q->active.next, struct cx23885_buffer,
@@ -652,13 +652,13 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (dev->tvnorm & V4L2_STD_NTSC) {
/* cx25840 transmits NTSC bottom field first */
dprintk(1, "%s() Creating NTSC risc\n",
- __FUNCTION__);
+ __func__);
line0_offset = buf->bpl;
line1_offset = 0;
} else {
/* All other formats are top field first */
dprintk(1, "%s() Creating PAL/SECAM risc\n",
- __FUNCTION__);
+ __func__);
line0_offset = 0;
line1_offset = buf->bpl;
}
@@ -979,7 +979,7 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma)
int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
{
- dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__);
+ dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
return 0;
}
@@ -988,7 +988,7 @@ EXPORT_SYMBOL(cx23885_get_control);
int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
{
dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
- " (disabled - no action)\n", __FUNCTION__);
+ " (disabled - no action)\n", __func__);
#if 0
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, ctl);
#endif
@@ -1012,7 +1012,7 @@ static void init_controls(struct cx23885_dev *dev)
/* ------------------------------------------------------------------ */
/* VIDEO IOCTLS */
-static int vidioc_g_fmt_cap(struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx23885_fh *fh = priv;
@@ -1029,7 +1029,7 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_try_fmt_cap(struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
@@ -1080,15 +1080,15 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
int err;
- dprintk(2, "%s()\n", __FUNCTION__);
- err = vidioc_try_fmt_cap(file, priv, f);
+ dprintk(2, "%s()\n", __func__);
+ err = vidioc_try_fmt_vid_cap(file, priv, f);
if (0 != err)
return err;
@@ -1096,7 +1096,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
fh->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height;
fh->vidq.field = f->fmt.pix.field;
- dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__,
+ dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
fh->width, fh->height, fh->vidq.field);
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
return 0;
@@ -1125,7 +1125,7 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_fmt_cap(struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (unlikely(f->index >= ARRAY_SIZE(formats)))
@@ -1201,7 +1201,7 @@ static int vidioc_streamon(struct file *file, void *priv,
{
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = fh->dev;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
return -EINVAL;
@@ -1218,7 +1218,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = fh->dev;
int err, res;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -1236,7 +1236,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
mutex_lock(&dev->lock);
cx23885_set_tvnorm(dev, *tvnorms);
@@ -1259,7 +1259,7 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
[CX23885_VMUX_DEBUG] = "for debug only",
};
unsigned int n;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
n = i->index;
if (n >= 4)
@@ -1284,7 +1284,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
return cx23885_enum_input(dev, i);
}
@@ -1293,7 +1293,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
*i = dev->input;
- dprintk(1, "%s() returns %d\n", __FUNCTION__, *i);
+ dprintk(1, "%s() returns %d\n", __func__, *i);
return 0;
}
@@ -1301,10 +1301,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- dprintk(1, "%s(%d)\n", __FUNCTION__, i);
+ dprintk(1, "%s(%d)\n", __func__, i);
if (i >= 4) {
- dprintk(1, "%s() -EINVAL\n", __FUNCTION__);
+ dprintk(1, "%s() -EINVAL\n", __func__);
return -EINVAL;
}
@@ -1594,7 +1594,7 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
return handled;
cx_write(VID_A_INT_STAT, status);
- dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status);
+ dprintk(2, "%s() status = 0x%08x\n", __func__, status);
/* risc op code error */
if (status & (1 << 16)) {
printk(KERN_WARNING "%s/0: video risc op code error\n",
@@ -1667,13 +1667,13 @@ static struct video_device cx23885_video_template = {
.fops = &video_fops,
.minor = -1,
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
- .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
- .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
- .vidioc_g_fmt_vbi = cx23885_vbi_fmt,
- .vidioc_try_fmt_vbi = cx23885_vbi_fmt,
- .vidioc_s_fmt_vbi = cx23885_vbi_fmt,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt,
+ .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt,
+ .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
@@ -1736,7 +1736,7 @@ static struct video_device cx23885_radio_template = {
void cx23885_video_unregister(struct cx23885_dev *dev)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
cx_clear(PCI_INT_MSK, 1);
#if 0
@@ -1771,7 +1771,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
{
int err;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
spin_lock_init(&dev->slock);
/* Initialize VBI template */
diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h
index d66fe2484..11ad18af6 100644
--- a/linux/drivers/media/video/cx23885/cx23885.h
+++ b/linux/drivers/media/video/cx23885/cx23885.h
@@ -33,6 +33,7 @@
#include "btcx-risc.h"
#include "cx23885-reg.h"
+#include "media/cx2341x.h"
#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
@@ -62,6 +63,10 @@
#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4
#define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5
#define CX23885_BOARD_HAUPPAUGE_HVR1500 6
+#define CX23885_BOARD_HAUPPAUGE_HVR1200 7
+#define CX23885_BOARD_HAUPPAUGE_HVR1700 8
+#define CX23885_BOARD_HAUPPAUGE_HVR1400 9
+#define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
@@ -157,6 +162,7 @@ typedef enum {
CX23885_MPEG_UNDEFINED = 0,
CX23885_MPEG_DVB,
CX23885_ANALOG_VIDEO,
+ CX23885_MPEG_ENCODER,
} port_t;
struct cx23885_board {
@@ -255,6 +261,8 @@ struct cx23885_tsport {
u32 gen_ctrl_val;
u32 ts_clk_en_val;
u32 src_sel_val;
+ u32 vld_misc_val;
+ u32 hw_sop_ctrl_val;
};
struct cx23885_dev {
@@ -319,6 +327,14 @@ struct cx23885_dev {
struct cx23885_dmaqueue vidq;
struct cx23885_dmaqueue vbiq;
spinlock_t slock;
+
+ /* MPEG Encoder ONLY settings */
+ u32 cx23417_mailbox;
+ struct cx2341x_mpeg_params mpeg_params;
+ struct video_device *v4l_device;
+ atomic_t v4l_reader_count;
+ struct cx23885_tvnorm encodernorm;
+
};
extern struct list_head cx23885_devlist;
@@ -438,6 +454,18 @@ extern int cx23885_i2c_register(struct cx23885_i2c *bus);
extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
void *arg);
+extern void cx23885_av_clk(struct cx23885_dev *dev, int enable);
+
+/* ----------------------------------------------------------- */
+/* cx23885-417.c */
+extern int cx23885_417_register(struct cx23885_dev *dev);
+extern void cx23885_417_unregister(struct cx23885_dev *dev);
+extern int cx23885_irq_417(struct cx23885_dev *dev, u32 status);
+extern void cx23885_417_check_encoder(struct cx23885_dev *dev);
+extern void cx23885_mc417_init(struct cx23885_dev *dev);
+extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
+extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+
/* ----------------------------------------------------------- */
/* tv norms */
diff --git a/linux/drivers/media/video/cx25840/Kconfig b/linux/drivers/media/video/cx25840/Kconfig
index 7cf29a03e..448f4cd0c 100644
--- a/linux/drivers/media/video/cx25840/Kconfig
+++ b/linux/drivers/media/video/cx25840/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_CX25840
tristate "Conexant CX2584x audio/video decoders"
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ depends on HOTPLUG # due to FW_LOADER
select FW_LOADER
---help---
Support for the Conexant CX2584x audio/video decoders.
diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c
index 82e7fb267..ca5cc0f51 100644
--- a/linux/drivers/media/video/cx25840/cx25840-core.c
+++ b/linux/drivers/media/video/cx25840/cx25840-core.c
@@ -462,7 +462,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
int chroma = vid_input & 0xf00;
if ((vid_input & ~0xff0) ||
- luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
+ luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 ||
chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
v4l_err(client, "0x%04x is not a valid video input!\n",
vid_input);
@@ -1238,7 +1238,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
/* ----------------------------------------------------------------------- */
-static int cx25840_probe(struct i2c_client *client)
+static int cx25840_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct cx25840_state *state;
u32 id;
@@ -1297,6 +1298,12 @@ static int cx25840_probe(struct i2c_client *client)
state->id = id;
state->rev = device_id;
+ if (state->is_cx23885) {
+ /* Drive GPIO2 direction and values */
+ cx25840_write(client, 0x160, 0x1d);
+ cx25840_write(client, 0x164, 0x00);
+ }
+
return 0;
}
@@ -1306,10 +1313,21 @@ static int cx25840_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id cx25840_id[] = {
+ { "cx25840", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cx25840_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "cx25840",
.driverid = I2C_DRIVERID_CX25840,
.command = cx25840_command,
.probe = cx25840_probe,
.remove = cx25840_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = cx25840_id,
+#endif
};
diff --git a/linux/drivers/media/video/cx88/Kconfig b/linux/drivers/media/video/cx88/Kconfig
index bcf6d9ba0..10e20d819 100644
--- a/linux/drivers/media/video/cx88/Kconfig
+++ b/linux/drivers/media/video/cx88/Kconfig
@@ -2,7 +2,6 @@ config VIDEO_CX88
tristate "Conexant 2388x (bt878 successor) support"
depends on VIDEO_DEV && PCI && I2C && INPUT
select I2C_ALGOBIT
- select FW_LOADER
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
select VIDEO_TUNER
@@ -34,8 +33,9 @@ config VIDEO_CX88_ALSA
config VIDEO_CX88_BLACKBIRD
tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
- depends on VIDEO_CX88
+ depends on VIDEO_CX88 && HOTPLUG
select VIDEO_CX2341X
+ select FW_LOADER
---help---
This adds support for MPEG encoder cards based on the
Blackbird reference design, using the Conexant 2388x
@@ -57,7 +57,8 @@ config VIDEO_CX88_DVB
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB/ATSC cards based on the
Conexant 2388x chip.
diff --git a/linux/drivers/media/video/cx88/Makefile b/linux/drivers/media/video/cx88/Makefile
index 532cee35e..6ec30f242 100644
--- a/linux/drivers/media/video/cx88/Makefile
+++ b/linux/drivers/media/video/cx88/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
index 56adb9c19..9e87bcb98 100644
--- a/linux/drivers/media/video/cx88/cx88-alsa.c
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -553,7 +553,7 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
#endif
count = atomic_read(&chip->count);
-// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__,
+// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__,
// count, new, count & (runtime->periods-1),
// runtime->period_size * (count & (runtime->periods-1)));
return runtime->period_size * (count & (runtime->periods-1));
@@ -755,10 +755,8 @@ MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
static int snd_cx88_free(snd_cx88_card_t *chip)
{
- if (chip->irq >= 0){
- synchronize_irq(chip->irq);
+ if (chip->irq >= 0)
free_irq(chip->irq, chip);
- }
cx88_core_put(chip->core,chip->pci);
diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c
index ab409da51..781beeb7f 100644
--- a/linux/drivers/media/video/cx88/cx88-blackbird.c
+++ b/linux/drivers/media/video/cx88/cx88-blackbird.c
@@ -319,7 +319,7 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat
u32 value, flag, retval;
int i;
- dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
+ dprintk(1,"%s: 0x%X\n", __func__, command);
/* this may not be 100% safe if we can't read any memory location
without side effects */
@@ -556,10 +556,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
if (retval < 0)
return retval;
- dev->mailbox = blackbird_find_mailbox(dev);
- if (dev->mailbox < 0)
+ retval = blackbird_find_mailbox(dev);
+ if (retval < 0)
return -1;
+ dev->mailbox = retval;
+
retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
dprintk(0, "ERROR: Firmware ping failed!\n");
@@ -757,7 +759,7 @@ static int vidioc_querycap (struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (f->index != 0)
@@ -769,7 +771,7 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_fmt_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx8802_fh *fh = priv;
@@ -788,7 +790,7 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_try_fmt_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx8802_fh *fh = priv;
@@ -804,7 +806,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_s_fmt_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx8802_fh *fh = priv;
@@ -1081,7 +1083,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
dev = cx8802_get_device(inode);
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
if (dev == NULL)
return -ENODEV;
@@ -1091,7 +1093,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
if (drv) {
err = drv->request_acquire(drv);
if(err != 0) {
- dprintk(1,"%s: Unable to acquire hardware, %d\n", __FUNCTION__, err);
+ dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
return err;
}
}
@@ -1205,10 +1207,10 @@ static struct video_device cx8802_mpeg_template =
.minor = -1,
.vidioc_querymenu = vidioc_querymenu,
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
- .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
- .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
@@ -1313,7 +1315,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
struct cx8802_dev *dev = core->dvbdev;
int err;
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
core->boardnr,
core->name,
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c
index fcecfeed9..1fb39e08e 100644
--- a/linux/drivers/media/video/cx88/cx88-cards.c
+++ b/linux/drivers/media/video/cx88/cx88-cards.c
@@ -71,6 +71,9 @@ MODULE_PARM_DESC(latency,"pci latency timer");
/* ------------------------------------------------------------------ */
/* board config info */
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
@@ -1410,6 +1413,10 @@ static const struct cx88_board cx88_boards[] = {
}},
/* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0xe780,
+ },
},
[CX88_BOARD_ADSTECH_PTV_390] = {
.name = "ADS Tech Instant Video PCI",
@@ -1536,10 +1543,16 @@ static const struct cx88_board cx88_boards[] = {
},
},
[CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
- .name = "PowerColor Real Angel 330",
+ .name = "PowerColor RA330", /* Long names may confuse LIRC. */
.tuner_type = TUNER_XC2028,
.tuner_addr = 0x61,
.input = { {
+ .type = CX88_VMUX_DEBUG,
+ .vmux = 3, /* Due to the way the cx88 driver is written, */
+ .gpio0 = 0x00ff, /* there is no way to deactivate audio pass- */
+ .gpio1 = 0xf39d, /* through without this entry. Furthermore, if */
+ .gpio3 = 0x0000, /* the TV mux entry is first, you get audio */
+ }, { /* from the tuner on boot for a little while. */
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00ff,
@@ -1637,6 +1650,7 @@ static const struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x16d9,
}},
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PROLINK_PV_8000GT] = {
.name = "Prolink Pixelview MPEG 8000GT",
@@ -2466,8 +2480,9 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
switch (core->boardnr) {
case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
- /* Doesn't work with firmware version 2.7 */
- ctl->fname = "xc3028-v25.fw";
+ /* Now works with firmware version 2.7 */
+ if (core->i2c_algo.udelay < 16)
+ core->i2c_algo.udelay = 16;
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
ctl->scode_table = XC3028_FE_ZARLINK456;
@@ -2491,25 +2506,31 @@ EXPORT_SYMBOL_GPL(cx88_setup_xc3028);
static void cx88_card_setup(struct cx88_core *core)
{
static u8 eeprom[256];
+ struct tuner_setup tun_setup;
+ unsigned int mode_mask = T_RADIO |
+ T_ANALOG_TV |
+ T_DIGITAL_TV;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
if (0 == core->i2c_rc) {
core->i2c_client.addr = 0xa0 >> 1;
- tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom));
+ tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom));
}
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_ROSLYN:
if (0 == core->i2c_rc)
- hauppauge_eeprom(core,eeprom+8);
+ hauppauge_eeprom(core, eeprom+8);
break;
case CX88_BOARD_GDI:
if (0 == core->i2c_rc)
- gdi_eeprom(core,eeprom);
+ gdi_eeprom(core, eeprom);
break;
case CX88_BOARD_WINFAST2000XP_EXPERT:
if (0 == core->i2c_rc)
- leadtek_eeprom(core,eeprom);
+ leadtek_eeprom(core, eeprom);
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
@@ -2519,7 +2540,7 @@ static void cx88_card_setup(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR1300:
if (0 == core->i2c_rc)
- hauppauge_eeprom(core,eeprom);
+ hauppauge_eeprom(core, eeprom);
break;
case CX88_BOARD_KWORLD_DVBS_100:
cx_write(MO_GP0_IO, 0x000007f8);
@@ -2600,6 +2621,35 @@ static void cx88_card_setup(struct cx88_core *core)
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
}
+ } /*end switch() */
+
+
+ /* Setup tuners */
+ if ((core->board.radio_type != UNSET)) {
+ tun_setup.mode_mask = T_RADIO;
+ tun_setup.type = core->board.radio_type;
+ tun_setup.addr = core->board.radio_addr;
+ tun_setup.tuner_callback = cx88_tuner_callback;
+ cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+ if (core->board.tuner_type != TUNER_ABSENT) {
+ tun_setup.mode_mask = mode_mask;
+ tun_setup.type = core->board.tuner_type;
+ tun_setup.addr = core->board.tuner_addr;
+ tun_setup.tuner_callback = cx88_tuner_callback;
+
+ cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
+ if (core->board.tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &core->board.tda9887_conf;
+
+ cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg);
}
if (core->board.tuner_type == TUNER_XC2028) {
@@ -2617,6 +2667,7 @@ static void cx88_card_setup(struct cx88_core *core)
ctl.fname);
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
}
+ cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
}
/* ------------------------------------------------------------------ */
@@ -2755,7 +2806,6 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
if (TUNER_ABSENT != core->board.tuner_type)
request_module("tuner");
- cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
cx88_card_setup(core);
cx88_ir_init(core, pci);
diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c
index a580d3706..5d6265c1d 100644
--- a/linux/drivers/media/video/cx88/cx88-core.c
+++ b/linux/drivers/media/video/cx88/cx88-core.c
@@ -73,7 +73,7 @@ static DEFINE_MUTEX(devlist);
/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
generated _after_ lpi lines are transferred. */
-static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
+static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines, unsigned int lpi)
@@ -133,7 +133,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int bpl, unsigned int padding, unsigned int lines)
{
u32 instructions,fields;
- u32 *rp;
+ __le32 *rp;
int rc;
fields = 0;
@@ -171,7 +171,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int lines, unsigned int lpi)
{
u32 instructions;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -196,7 +196,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value)
{
- u32 *rp;
+ __le32 *rp;
int rc;
if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
@@ -575,7 +575,7 @@ void cx88_wakeup(struct cx88_core *core,
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
}
if (bc != 1)
- printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+ printk("%s: %d buffers handled (should be 1)\n",__func__,bc);
}
void cx88_shutdown(struct cx88_core *core)
@@ -604,7 +604,7 @@ void cx88_shutdown(struct cx88_core *core)
int cx88_reset(struct cx88_core *core)
{
- dprintk(1,"%s\n",__FUNCTION__);
+ dprintk(1,"%s\n",__func__);
cx88_shutdown(core);
/* clear irq status */
diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c
index ab31fdc80..fc5807aeb 100644
--- a/linux/drivers/media/video/cx88/cx88-dvb.c
+++ b/linux/drivers/media/video/cx88/cx88-dvb.c
@@ -46,9 +46,9 @@
#include "nxt200x.h"
#include "cx24123.h"
#include "isl6421.h"
-#include "tuner-xc2028-types.h"
#include "tuner-simple.h"
#include "tda9887.h"
+#include "s5h1411.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -59,6 +59,8 @@ static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
#define dprintk(level,fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
@@ -283,7 +285,7 @@ static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
- dprintk(1, "%s: index = %d\n", __FUNCTION__, index);
+ dprintk(1, "%s: index = %d\n", __func__, index);
if (index == 0)
cx_clear(MO_GP0_IO, 8);
else
@@ -381,7 +383,7 @@ static int cx88_pci_nano_callback(void *ptr, int command, int arg)
switch (command) {
case XC2028_TUNER_RESET:
/* Send the tuner in then out of reset */
- dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+ dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
switch (core->boardnr) {
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
@@ -397,10 +399,10 @@ static int cx88_pci_nano_callback(void *ptr, int command, int arg)
break;
case XC2028_RESET_CLK:
- dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+ dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
break;
default:
- dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
+ dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
command, arg);
return -EINVAL;
}
@@ -469,6 +471,22 @@ static struct zl10353_config cx88_geniatech_x8000_mt = {
#endif
};
+static struct s5h1411_config dvico_fusionhdtv7_config = {
+ .output_mode = S5H1411_SERIAL_OUTPUT,
+ .gpio = S5H1411_GPIO_ON,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+ .qam_if = S5H1411_IF_44000,
+ .vsb_if = S5H1411_IF_44000,
+ .inversion = S5H1411_INVERSION_OFF,
+ .status_mode = S5H1411_DEMODLOCKING
+};
+
+static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
+ .i2c_address = 0xc2 >> 1,
+ .if_khz = 5380,
+ .tuner_callback = cx88_tuner_callback,
+};
+
static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
{
struct dvb_frontend *fe;
@@ -498,9 +516,6 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
if (!fe) {
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->core->name);
- dvb_frontend_detach(dev->dvb.frontend);
- dvb_unregister_frontend(dev->dvb.frontend);
- dev->dvb.frontend = NULL;
return -EINVAL;
}
@@ -512,20 +527,23 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
static int dvb_register(struct cx8802_dev *dev)
{
+ struct cx88_core *core = dev->core;
+
/* init struct videobuf_dvb */
- dev->dvb.name = dev->core->name;
+ dev->dvb.name = core->name;
dev->ts_gen_cntrl = 0x0c;
/* init frontend */
- switch (dev->core->boardnr) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- DVB_PLL_THOMSON_DTT759X);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, &core->i2c_adap,
+ DVB_PLL_THOMSON_DTT759X))
+ goto frontend_detach;
}
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -534,11 +552,12 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- &dev->core->i2c_adap,
- DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x60, &core->i2c_adap,
+ DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
}
break;
case CX88_BOARD_WINFAST_DTV2000H:
@@ -548,29 +567,32 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_HVR3000:
dev->dvb.frontend = dvb_attach(cx22702_attach,
&hauppauge_hvr_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_PHILIPS_FMD1216ME_MK3);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
dev->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
break;
}
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_plus_v1_1,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -578,28 +600,31 @@ static int dvb_register(struct cx8802_dev *dev)
* compatible, with a slightly different MT352 AGC gain. */
dev->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv_dual,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
break;
}
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_plus_v1_1,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
dev->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_LG_Z201);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, NULL, DVB_PLL_LG_Z201))
+ goto frontend_detach;
}
break;
case CX88_BOARD_KWORLD_DVB_T:
@@ -607,10 +632,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_ADSTECH_DVB_T_PCI:
dev->dvb.frontend = dvb_attach(mt352_attach,
&dntv_live_dvbt_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_UNKNOWN_1);
+ if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+ 0x61, NULL, DVB_PLL_UNKNOWN_1))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
@@ -619,32 +645,35 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&dev->vp3054->adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_PHILIPS_FMD1216ME_MK3);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3))
+ goto frontend_detach;
}
#else
- printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
+ printk(KERN_ERR "%s/2: built without vp3054 support\n",
+ core->name);
#endif
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
dev->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_hybrid,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_THOMSON_FE6600);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_FE6600))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
dev->dvb.frontend = dvb_attach(zl10353_attach,
&dvico_fusionhdtv_xc3028,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend == NULL)
dev->dvb.frontend = dvb_attach(mt352_attach,
&dvico_fusionhdtv_mt352_xc3028,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
/*
* On this board, the demod provides the I2C bus pullup.
* We must not permit gate_ctrl to be performed, or
@@ -657,19 +686,18 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_THOMSON_DTT761X);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_DTT761X))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
dev->ts_gen_cntrl = 0x08;
- {
- /* Do a hardware reset of chip before using it. */
- struct cx88_core *core = dev->core;
+ /* Do a hardware reset of chip before using it. */
cx_clear(MO_GP0_IO, 1);
mdelay(100);
cx_set(MO_GP0_IO, 1);
@@ -679,146 +707,144 @@ static int dvb_register(struct cx8802_dev *dev)
fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_3_gold,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_MICROTUNE_4042FI5);
- }
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_MICROTUNE_4042FI5))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
dev->ts_gen_cntrl = 0x08;
- {
- /* Do a hardware reset of chip before using it. */
- struct cx88_core *core = dev->core;
+ /* Do a hardware reset of chip before using it. */
cx_clear(MO_GP0_IO, 1);
mdelay(100);
cx_set(MO_GP0_IO, 9);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_3_gold,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_THOMSON_DTT761X);
- }
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_THOMSON_DTT761X))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
dev->ts_gen_cntrl = 0x08;
- {
- /* Do a hardware reset of chip before using it. */
- struct cx88_core *core = dev->core;
+ /* Do a hardware reset of chip before using it. */
cx_clear(MO_GP0_IO, 1);
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_5_gold,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF);
- dvb_attach(tda9887_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x43);
- }
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF))
+ goto frontend_detach;
+ if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x43))
+ goto frontend_detach;
}
break;
case CX88_BOARD_PCHDTV_HD5500:
dev->ts_gen_cntrl = 0x08;
- {
- /* Do a hardware reset of chip before using it. */
- struct cx88_core *core = dev->core;
+ /* Do a hardware reset of chip before using it. */
cx_clear(MO_GP0_IO, 1);
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
dev->dvb.frontend = dvb_attach(lgdt330x_attach,
&pchdtv_hd5500,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF);
- dvb_attach(tda9887_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x43);
- }
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF))
+ goto frontend_detach;
+ if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x43))
+ goto frontend_detach;
}
break;
case CX88_BOARD_ATI_HDTVWONDER:
dev->dvb.frontend = dvb_attach(nxt200x_attach,
&ati_hdtvwonder,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x61,
- TUNER_PHILIPS_TUV1236D);
+ if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x61,
+ TUNER_PHILIPS_TUV1236D))
+ goto frontend_detach;
}
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
dev->dvb.frontend = dvb_attach(cx24123_attach,
&hauppauge_novas_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend) {
- dvb_attach(isl6421_attach, dev->dvb.frontend,
- &dev->core->i2c_adap, 0x08, 0x00, 0x00);
+ if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
+ &core->i2c_adap, 0x08, 0x00, 0x00))
+ goto frontend_detach;
}
break;
case CX88_BOARD_KWORLD_DVBS_100:
dev->dvb.frontend = dvb_attach(cx24123_attach,
&kworld_dvbs_100_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend) {
- dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
}
break;
case CX88_BOARD_GENIATECH_DVBS:
dev->dvb.frontend = dvb_attach(cx24123_attach,
&geniatech_dvbs_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend) {
- dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
}
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
&pinnacle_pctv_hd_800i_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
/* tuner_config.video_dev must point to
* i2c_adap.algo_data
*/
- pinnacle_pctv_hd_800i_tuner_config.priv =
- dev->core->i2c_adap.algo_data;
- dvb_attach(xc5000_attach, dev->dvb.frontend,
- &dev->core->i2c_adap,
- &pinnacle_pctv_hd_800i_tuner_config);
+ if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+ &core->i2c_adap,
+ &pinnacle_pctv_hd_800i_tuner_config,
+ core->i2c_adap.algo_data))
+ goto frontend_detach;
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
&dvico_hdtv5_pci_nano_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (dev->dvb.frontend != NULL) {
struct dvb_frontend *fe;
struct xc2028_config cfg = {
- .i2c_adap = &dev->core->i2c_adap,
+ .i2c_adap = &core->i2c_adap,
.i2c_addr = 0x61,
.callback = cx88_pci_nano_callback,
};
static struct xc2028_ctrl ctl = {
.fname = "xc3028-v27.fw",
.max_len = 64,
- .scode_table = OREN538,
+ .scode_table = XC3028_FE_OREN538,
};
fe = dvb_attach(xc2028_attach,
@@ -830,35 +856,50 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_PINNACLE_HYBRID_PCTV:
dev->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_geniatech_x8000_mt,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
- return -EINVAL;
+ goto frontend_detach;
break;
case CX88_BOARD_GENIATECH_X8000_MT:
dev->ts_gen_cntrl = 0x00;
dev->dvb.frontend = dvb_attach(zl10353_attach,
&cx88_geniatech_x8000_mt,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
- return -EINVAL;
+ goto frontend_detach;
break;
case CX88_BOARD_KWORLD_ATSC_120:
dev->dvb.frontend = dvb_attach(s5h1409_attach,
&kworld_atsc_120_config,
- &dev->core->i2c_adap);
+ &core->i2c_adap);
if (attach_xc3028(0x61, dev) < 0)
- return -EINVAL;
+ goto frontend_detach;
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+ dev->dvb.frontend = dvb_attach(s5h1411_attach,
+ &dvico_fusionhdtv7_config,
+ &core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ /* tuner_config.video_dev must point to
+ * i2c_adap.algo_data
+ */
+ if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+ &core->i2c_adap,
+ &dvico_fusionhdtv7_tuner_config,
+ core->i2c_adap.algo_data))
+ goto frontend_detach;
+ }
break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
- dev->core->name);
+ core->name);
break;
}
if (NULL == dev->dvb.frontend) {
printk(KERN_ERR
"%s/2: frontend initialization failed\n",
- dev->core->name);
+ core->name);
return -EINVAL;
}
@@ -866,10 +907,18 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
/* Put the analog decoder in standby to keep it quiet */
- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+ cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
/* register everything */
- return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
+ &dev->pci->dev, adapter_nr);
+
+frontend_detach:
+ if (dev->dvb.frontend) {
+ dvb_frontend_detach(dev->dvb.frontend);
+ dev->dvb.frontend = NULL;
+ }
+ return -EINVAL;
}
/* ----------------------------------------------------------- */
@@ -879,7 +928,7 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
int err = 0;
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -902,7 +951,7 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
int err = 0;
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -923,7 +972,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
struct cx8802_dev *dev = drv->core->dvbdev;
int err;
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
core->boardnr,
core->name,
@@ -961,7 +1010,8 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
struct cx8802_dev *dev = drv->core->dvbdev;
/* dvb */
- videobuf_dvb_unregister(&dev->dvb);
+ if (dev->dvb.frontend)
+ videobuf_dvb_unregister(&dev->dvb);
vp3054_i2c_remove(dev);
diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c
index 44d01352e..800ea0d64 100644
--- a/linux/drivers/media/video/cx88/cx88-i2c.c
+++ b/linux/drivers/media/video/cx88/cx88-i2c.c
@@ -102,7 +102,6 @@ static int cx8800_bit_getsda(void *data)
static int attach_inform(struct i2c_client *client)
{
- struct tuner_setup tun_setup;
struct cx88_core *core = i2c_get_adapdata(client->adapter);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
@@ -112,37 +111,7 @@ static int attach_inform(struct i2c_client *client)
dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
client->driver->driver.name, client->addr, client->name);
#endif
- if (!client->driver->command)
- return 0;
-
- if (core->board.radio_type != UNSET) {
- if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
- tun_setup.mode_mask = T_RADIO;
- tun_setup.type = core->board.radio_type;
- tun_setup.addr = core->board.radio_addr;
- tun_setup.tuner_callback = cx88_tuner_callback;
- client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
- if (core->board.tuner_type != UNSET) {
- if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
-
- tun_setup.mode_mask = T_ANALOG_TV;
- tun_setup.type = core->board.tuner_type;
- tun_setup.addr = core->board.tuner_addr;
- tun_setup.tuner_callback = cx88_tuner_callback;
- client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
-
- if (core->board.tda9887_conf) {
- struct v4l2_priv_tun_config tda9887_cfg;
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &core->board.tda9887_conf;
-
- client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg);
- }
return 0;
}
diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c
index 6ec40f79f..c8dba3dfa 100644
--- a/linux/drivers/media/video/cx88/cx88-mpeg.c
+++ b/linux/drivers/media/video/cx88/cx88-mpeg.c
@@ -175,7 +175,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
udelay(100);
} else {
- printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
+ printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __func__,
core->board.mpeg );
return -EINVAL;
}
@@ -279,7 +279,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
int rc;
- dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+ dprintk(1, "%s: %p\n", __func__, buf);
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
@@ -321,7 +321,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
buf->count = cx88q->count++;
mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
dprintk(1,"[%p/%d] %s - first active\n",
- buf, buf->vb.i, __FUNCTION__);
+ buf, buf->vb.i, __func__);
#if 0
udelay(100);
#endif
@@ -334,7 +334,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
buf->count = cx88q->count++;
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
dprintk( 1, "[%p/%d] %s - append to active\n",
- buf, buf->vb.i, __FUNCTION__);
+ buf, buf->vb.i, __func__);
#if 0
udelay(100);
#endif
@@ -380,7 +380,7 @@ static void cx8802_timeout(unsigned long data)
{
struct cx8802_dev *dev = (struct cx8802_dev*)data;
- dprintk(1, "%s\n",__FUNCTION__);
+ dprintk(1, "%s\n",__func__);
if (debug)
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
@@ -683,7 +683,7 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
}
mutex_unlock(&drv->core->lock);
- mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+ mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
}
return 0;
@@ -699,7 +699,7 @@ static int cx8802_request_release(struct cx8802_driver *drv)
{
drv->advise_release(drv);
core->active_type_id = CX88_BOARD_NONE;
- mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+ mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
}
mutex_unlock(&drv->core->lock);
@@ -873,7 +873,7 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
dev = pci_get_drvdata(pci_dev);
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
if (!list_empty(&dev->drvlist)) {
struct cx8802_driver *drv, *tmp;
diff --git a/linux/drivers/media/video/cx88/cx88-tvaudio.c b/linux/drivers/media/video/cx88/cx88-tvaudio.c
index d2e1fdb91..b4dab2647 100644
--- a/linux/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/linux/drivers/media/video/cx88/cx88-tvaudio.c
@@ -271,12 +271,12 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
mode |= EN_FMRADIO_EN_RDS;
if (sap) {
- dprintk("%s SAP (status: unknown)\n", __FUNCTION__);
+ dprintk("%s SAP (status: unknown)\n", __func__);
set_audio_start(core, SEL_SAP);
set_audio_registers(core, btsc_sap);
set_audio_finish(core, mode);
} else {
- dprintk("%s (status: known-good)\n", __FUNCTION__);
+ dprintk("%s (status: known-good)\n", __func__);
set_audio_start(core, SEL_BTSC);
set_audio_registers(core, btsc);
set_audio_finish(core, mode);
@@ -357,16 +357,16 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
set_audio_start(core,SEL_NICAM);
switch (core->tvaudio) {
case WW_L:
- dprintk("%s SECAM-L NICAM (status: devel)\n", __FUNCTION__);
+ dprintk("%s SECAM-L NICAM (status: devel)\n", __func__);
set_audio_registers(core, nicam_l);
break;
case WW_I:
- dprintk("%s PAL-I NICAM (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-I NICAM (status: known-good)\n", __func__);
set_audio_registers(core, nicam_bgdki_common);
set_audio_registers(core, nicam_i);
break;
default:
- dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__);
set_audio_registers(core, nicam_bgdki_common);
set_audio_registers(core, nicam_default);
break;
@@ -606,28 +606,28 @@ static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
set_audio_start(core, SEL_A2);
switch (core->tvaudio) {
case WW_BG:
- dprintk("%s PAL-BG A1/2 (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__);
set_audio_registers(core, a2_bgdk_common);
set_audio_registers(core, a2_bg);
set_audio_registers(core, a2_deemph50);
break;
case WW_DK:
- dprintk("%s PAL-DK A1/2 (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__);
set_audio_registers(core, a2_bgdk_common);
set_audio_registers(core, a2_dk);
set_audio_registers(core, a2_deemph50);
break;
case WW_I:
- dprintk("%s PAL-I A1 (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-I A1 (status: known-good)\n", __func__);
set_audio_registers(core, a1_i);
set_audio_registers(core, a2_deemph50);
break;
case WW_L:
- dprintk("%s AM-L (status: devel)\n", __FUNCTION__);
+ dprintk("%s AM-L (status: devel)\n", __func__);
set_audio_registers(core, am_l);
break;
default:
- dprintk("%s Warning: wrong value\n", __FUNCTION__);
+ dprintk("%s Warning: wrong value\n", __func__);
return;
break;
};
@@ -643,7 +643,7 @@ static void set_audio_standard_EIAJ(struct cx88_core *core)
{ /* end of list */ },
};
- dprintk("%s (status: unknown)\n", __FUNCTION__);
+ dprintk("%s (status: unknown)\n", __func__);
set_audio_start(core, SEL_EIAJ);
set_audio_registers(core, eiaj);
@@ -697,7 +697,7 @@ static void set_audio_standard_FM(struct cx88_core *core,
{ /* end of list */ },
};
- dprintk("%s (status: unknown)\n", __FUNCTION__);
+ dprintk("%s (status: unknown)\n", __func__);
set_audio_start(core, SEL_FMRADIO);
switch (deemph) {
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index b25402467..c9f7d0048 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -1294,7 +1294,7 @@ static void init_controls(struct cx88_core *core)
/* ------------------------------------------------------------------ */
/* VIDEO IOCTLS */
-static int vidioc_g_fmt_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx8800_fh *fh = priv;
@@ -1310,7 +1310,7 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_try_fmt_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
@@ -1361,11 +1361,11 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_s_fmt_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx8800_fh *fh = priv;
- int err = vidioc_try_fmt_cap (file,priv,f);
+ int err = vidioc_try_fmt_vid_cap (file,priv,f);
if (0 != err)
return err;
@@ -1399,7 +1399,7 @@ static int vidioc_querycap (struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (unlikely(f->index >= ARRAY_SIZE(formats)))
@@ -1977,13 +1977,13 @@ static struct video_device cx8800_video_template =
.fops = &video_fops,
.minor = -1,
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
- .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
- .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
- .vidioc_g_fmt_vbi = cx8800_vbi_fmt,
- .vidioc_try_fmt_vbi = cx8800_vbi_fmt,
- .vidioc_s_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt,
+ .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt,
+ .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
diff --git a/linux/drivers/media/video/dpc7146.c b/linux/drivers/media/video/dpc7146.c
index 258d46407..4bfb3076b 100644
--- a/linux/drivers/media/video/dpc7146.c
+++ b/linux/drivers/media/video/dpc7146.c
@@ -132,7 +132,7 @@ static int dpc_probe(struct saa7146_dev* dev)
device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
/* check if all devices are present */
- if( 0 == dpc->saa7111a ) {
+ if (!dpc->saa7111a) {
DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
i2c_del_adapter(&dpc->i2c_adapter);
kfree(dpc);
diff --git a/linux/drivers/media/video/em28xx/Kconfig b/linux/drivers/media/video/em28xx/Kconfig
index 0f7a0bd86..16a5af30e 100644
--- a/linux/drivers/media/video/em28xx/Kconfig
+++ b/linux/drivers/media/video/em28xx/Kconfig
@@ -1,11 +1,13 @@
config VIDEO_EM28XX
- tristate "Empia EM2800/2820/2840 USB video capture support"
+ tristate "Empia EM28xx USB video capture support"
depends on VIDEO_DEV && I2C && INPUT
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
+ select VIDEOBUF_VMALLOC
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
---help---
This is a video4linux driver for Empia 28xx based TV cards.
@@ -27,3 +29,12 @@ config VIDEO_EM28XX_ALSA
To compile this driver as a module, choose M here: the
module will be called em28xx-alsa
+config VIDEO_EM28XX_DVB
+ tristate "DVB/ATSC Support for em28xx based TV cards"
+ depends on VIDEO_EM28XX && DVB_CORE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select VIDEOBUF_DVB
+ ---help---
+ This adds support for DVB cards based on the
+ Empiatech em28xx chips.
diff --git a/linux/drivers/media/video/em28xx/Makefile b/linux/drivers/media/video/em28xx/Makefile
index 092455099..8137a8c94 100644
--- a/linux/drivers/media/video/em28xx/Makefile
+++ b/linux/drivers/media/video/em28xx/Makefile
@@ -5,8 +5,10 @@ em28xx-alsa-objs := em28xx-audio.o
obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
+obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c
index 37e893455..609e28e77 100644
--- a/linux/drivers/media/video/em28xx/em28xx-audio.c
+++ b/linux/drivers/media/video/em28xx/em28xx-audio.c
@@ -52,7 +52,7 @@ MODULE_PARM_DESC(debug, "activates debug info");
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_INFO "em28xx-audio %s: " fmt, \
- __FUNCTION__, ##arg); \
+ __func__, ##arg); \
} while (0)
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 06a4e4a2b..c877c855e 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -37,7 +37,6 @@
#include <media/v4l2-common.h>
#include "em28xx.h"
-#include "tuner-xc2028.h"
static int tuner = -1;
module_param(tuner, int, 0444);
@@ -53,26 +52,6 @@ struct em28xx_hash_table {
unsigned int tuner;
};
-/* Boards supported by driver */
-
-#define EM2800_BOARD_UNKNOWN 0
-#define EM2820_BOARD_UNKNOWN 1
-#define EM2820_BOARD_TERRATEC_CINERGY_250 2
-#define EM2820_BOARD_PINNACLE_USB_2 3
-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
-#define EM2820_BOARD_MSI_VOX_USB_2 5
-#define EM2800_BOARD_TERRATEC_CINERGY_200 6
-#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
-#define EM2800_BOARD_KWORLD_USB2800 8
-#define EM2820_BOARD_PINNACLE_DVC_90 9
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
-#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
-#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
-#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
-#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
-#define EM2800_BOARD_VGEAR_POCKETTV 15
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16
-
struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_UNKNOWN] = {
.name = "Unknown EM2800 video grabber",
@@ -194,6 +173,27 @@ struct em28xx_board em28xx_boards[] = {
.amux = 1,
} },
},
+ [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = {
+ .name = "Hauppauge WinTV HVR 900 (R2)",
+ .vchannels = 3,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_XC2028,
+ .mts_firmware = 1,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = 0,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = 1,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = 1,
+ } },
+ },
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
.name = "Hauppauge WinTV HVR 950",
.vchannels = 3,
@@ -201,6 +201,30 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_XC2028,
.mts_firmware = 1,
.has_12mhz_i2s = 1,
+ .has_dvb = 1,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = 0,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = 1,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = 1,
+ } },
+ },
+ [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = {
+ .name = "Pinnacle PCTV HD Pro Stick",
+ .vchannels = 3,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_XC2028,
+ .mts_firmware = 1,
+ .has_12mhz_i2s = 1,
+ .has_dvb = 1,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -215,9 +239,6 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_SVIDEO,
.amux = 1,
} },
-
- /* gpio's 4, 1, 0 */
- .analog_gpio = 0x003d2d,
},
[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Hybrid XS",
@@ -440,11 +461,19 @@ struct usb_device_id em28xx_id_table [] = {
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
{ USB_DEVICE(0x2304, 0x021a),
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+ { USB_DEVICE(0x2304, 0x0227),
+ .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
{ USB_DEVICE(0x2040, 0x6500),
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
{ USB_DEVICE(0x2040, 0x6502),
- .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
- { USB_DEVICE(0x2040, 0x6513),
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 },
+ { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */
.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
{ USB_DEVICE(0x0ccd, 0x0042),
.driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
@@ -454,7 +483,36 @@ struct usb_device_id em28xx_id_table [] = {
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
-/* EEPROM hash table for devices with generic USB IDs */
+/*
+ * Reset sequences for analog/digital modes
+ */
+
+/* Board Hauppauge WinTV HVR 900 analog */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+ {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10},
+ {0x05, 0xff, 0x10, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+ {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x04, 0x0f, 10},
+ {EM2880_R04_GPO, 0x0c, 0x0f, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 tuner_callback */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_tuner_callback[] = {
+ {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10},
+ {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+/*
+ * EEPROM hash table for devices with generic USB IDs
+ */
static struct em28xx_hash_table em28xx_eeprom_hash [] = {
/* P/N: SA 60002070465 Tuner: TVF7533-MF */
{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
@@ -466,79 +524,120 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
};
+int em28xx_tuner_callback(void *ptr, int command, int arg)
+{
+ int rc = 0;
+ struct em28xx *dev = ptr;
+
+ if (dev->tuner_type != TUNER_XC2028)
+ return 0;
+
+ if (command != XC2028_TUNER_RESET)
+ return 0;
+
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_gpio_set(dev, dev->tun_analog_gpio);
+ else
+ rc = em28xx_gpio_set(dev, dev->tun_digital_gpio);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
+
+static void em28xx_set_model(struct em28xx *dev)
+{
+ dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
+ dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
+ dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+ dev->decoder = em28xx_boards[dev->model].decoder;
+ dev->video_inputs = em28xx_boards[dev->model].vchannels;
+ dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
+ dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
+ dev->has_dvb = em28xx_boards[dev->model].has_dvb;
+}
+
/* Since em28xx_pre_card_setup() requires a proper dev->model,
* this won't work for boards with generic PCI IDs
*/
void em28xx_pre_card_setup(struct em28xx *dev)
{
+ int rc;
+
+ rc = em28xx_read_reg(dev, EM2880_R04_GPO);
+ if (rc >= 0)
+ dev->reg_gpo = rc;
+
+ dev->wait_after_write = 5;
+ rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
+ if (rc > 0) {
+ switch (rc) {
+ case CHIP_ID_EM2883:
+ em28xx_info("chip ID is em2882/em2883\n");
+ dev->wait_after_write = 0;
+ break;
+ default:
+ em28xx_info("em28xx chip ID = %d\n", rc);
+ }
+ }
+ em28xx_set_model(dev);
+
/* request some modules */
switch (dev->model) {
case EM2880_BOARD_TERRATEC_PRODIGY_XS:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2880_BOARD_TERRATEC_HYBRID_XS:
- em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
- em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
- em28xx_write_regs(dev, 0x08, "\xff", 1);
- em28xx_write_regs(dev, 0x04, "\x00", 1);
- msleep(100);
- em28xx_write_regs(dev, 0x04, "\x08", 1);
- msleep(100);
- em28xx_write_regs(dev, 0x08, "\xff", 1);
- msleep(50);
- em28xx_write_regs(dev, 0x08, "\x2d", 1);
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+ em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
+ em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
msleep(50);
- em28xx_write_regs(dev, 0x08, "\x3d", 1);
+
+ /* Sets GPO/GPIO sequences for this device */
+ dev->analog_gpio = hauppauge_wintv_hvr_900_analog;
+ dev->digital_gpio = hauppauge_wintv_hvr_900_digital;
+ dev->tun_analog_gpio = hauppauge_wintv_hvr_900_tuner_callback;
+ dev->tun_digital_gpio = hauppauge_wintv_hvr_900_tuner_callback;
+
break;
}
+
+ em28xx_gpio_set(dev, dev->tun_analog_gpio);
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+
+ /* Unlock device */
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
}
-static int em28xx_tuner_callback(void *ptr, int command, int arg)
+static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
{
- int rc = 0;
- struct em28xx *dev = ptr;
+ memset(ctl, 0, sizeof(*ctl));
- if (dev->tuner_type != TUNER_XC2028)
- return 0;
-
- switch (command) {
- case XC2028_TUNER_RESET:
- {
- /* GPIO and initialization codes for analog TV and radio
- This code should be complemented for DTV, since reset
- codes are different.
- */
-
- dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
- dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
-
- if (dev->analog_gpio) {
- char gpio0 = dev->analog_gpio & 0xff;
- char gpio1 = (dev->analog_gpio >> 8) & 0xff;
- char gpio4 = dev->analog_gpio >> 24;
-
- if (gpio4) {
- dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
- msleep(140);
- }
-
- msleep(6);
- dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
- msleep(10);
- dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
- msleep(5);
- }
+ ctl->fname = XC2028_DEFAULT_FIRMWARE;
+ ctl->max_len = 64;
+ ctl->mts = em28xx_boards[dev->model].mts_firmware;
+ switch (dev->model) {
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ ctl->demod = XC3028_FE_ZARLINK456;
break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+ /* djh - Not sure which demod we need here */
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+ /* FIXME: Better to specify the needed IF */
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
+ default:
+ ctl->demod = XC3028_FE_OREN538;
}
- }
- return rc;
}
static void em28xx_config_tuner(struct em28xx *dev)
{
struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
struct tuner_setup tun_setup;
struct v4l2_frequency f;
@@ -553,11 +652,9 @@ static void em28xx_config_tuner(struct em28xx *dev)
em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
if (dev->tuner_type == TUNER_XC2028) {
- memset(&ctl, 0, sizeof(ctl));
+ struct xc2028_ctrl ctl;
- ctl.fname = XC2028_DEFAULT_FIRMWARE;
- ctl.max_len = 64;
- ctl.mts = em28xx_boards[dev->model].mts_firmware;
+ em28xx_setup_xc3028(dev, &ctl);
xc2028_cfg.tuner = TUNER_XC2028;
xc2028_cfg.priv = &ctl;
@@ -655,19 +752,6 @@ static int em28xx_hint_board(struct em28xx *dev)
return -1;
}
-
-static void em28xx_set_model(struct em28xx *dev)
-{
- dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
- dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
- dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
- dev->decoder = em28xx_boards[dev->model].decoder;
- dev->video_inputs = em28xx_boards[dev->model].vchannels;
- dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
- dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
- dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
-}
-
/* ----------------------------------------------------------------------- */
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
{
@@ -720,6 +804,7 @@ void em28xx_card_setup(struct em28xx *dev)
switch (dev->model) {
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
{
struct tveeprom tv;
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index 1f6abc803..1a30e361c 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -38,7 +38,7 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
#define em28xx_coredbg(fmt, arg...) do {\
if (core_debug) \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ dev->name, __func__ , ##arg); } while (0)
static unsigned int reg_debug;
module_param(reg_debug,int,0644);
@@ -47,139 +47,17 @@ MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
#define em28xx_regdbg(fmt, arg...) do {\
if (reg_debug) \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
-
-static unsigned int isoc_debug;
-module_param(isoc_debug,int,0644);
-MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
-
-#define em28xx_isocdbg(fmt, arg...) do {\
- if (isoc_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ dev->name, __func__ , ##arg); } while (0)
static int alt = EM28XX_PINOUT;
module_param(alt, int, 0644);
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
-#include <linux/mm.h>
-static void *rvmalloc(size_t size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
-
- mem = vmalloc_32((unsigned long)size);
- if (!mem)
- return NULL;
-
- adr = (unsigned long)mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-static void rvfree(void *mem, size_t size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- size = PAGE_ALIGN(size);
-
- adr = (unsigned long)mem;
- while (size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vfree(mem);
-}
-#endif
-
-/*
- * em28xx_request_buffers()
- * allocate a number of buffers
- */
-u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
-{
- const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */
- void *buff = NULL;
- u32 i;
- em28xx_coredbg("requested %i buffers with size %zi\n",
- count, imagesize);
- if (count > EM28XX_NUM_FRAMES)
- count = EM28XX_NUM_FRAMES;
-
- dev->num_frames = count;
- while (dev->num_frames > 0) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
- if ((buff = rvmalloc(dev->num_frames * imagesize))) {
-#else
- if ((buff = vmalloc_32(dev->num_frames * imagesize))) {
-#endif
- memset(buff, 0, dev->num_frames * imagesize);
- break;
- }
- dev->num_frames--;
- }
-
- for (i = 0; i < dev->num_frames; i++) {
- dev->frame[i].bufmem = buff + i * imagesize;
- dev->frame[i].buf.index = i;
- dev->frame[i].buf.m.offset = i * imagesize;
- dev->frame[i].buf.length = dev->frame_size;
- dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dev->frame[i].buf.sequence = 0;
- dev->frame[i].buf.field = V4L2_FIELD_NONE;
- dev->frame[i].buf.memory = V4L2_MEMORY_MMAP;
- dev->frame[i].buf.flags = 0;
- }
- return dev->num_frames;
-}
-
-/*
- * em28xx_queue_unusedframes()
- * add all frames that are not currently in use to the inbuffer queue
- */
-void em28xx_queue_unusedframes(struct em28xx *dev)
-{
- unsigned long lock_flags;
- u32 i;
-
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].state == F_UNUSED) {
- dev->frame[i].state = F_QUEUED;
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_add_tail(&dev->frame[i].frame, &dev->inqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
- }
-}
-
-/*
- * em28xx_release_buffers()
- * free frame buffers
- */
-void em28xx_release_buffers(struct em28xx *dev)
-{
- if (dev->num_frames) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
- rvfree(dev->frame[0].bufmem,
- dev->num_frames * PAGE_ALIGN(dev->frame[0].buf.length));
-#else
- vfree(dev->frame[0].bufmem);
-#endif
- dev->num_frames = 0;
- }
-}
+/* FIXME */
+#define em28xx_isocdbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
/*
* em28xx_read_reg_req()
@@ -199,11 +77,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, reg, buf, len, HZ);
- if (reg_debug){
+ if (reg_debug) {
printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
- for (byte = 0; byte < len; byte++) {
+ for (byte = 0; byte < len; byte++)
printk(" %02x", (unsigned char)buf[byte]);
- }
+
printk("\n");
}
@@ -256,7 +134,10 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
unsigned char *bufs;
if (dev->state & DEV_DISCONNECTED)
- return(-ENODEV);
+ return -ENODEV;
+
+ if (len < 1)
+ return -EINVAL;
bufs = kmalloc(len, GFP_KERNEL);
@@ -265,8 +146,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
if (reg_debug) {
int i;
for (i = 0; i < len; ++i)
- printk (" %02x", (unsigned char)buf[i]);
- printk ("\n");
+ printk(" %02x", (unsigned char)buf[i]);
+ printk("\n");
}
if (!bufs)
@@ -275,14 +156,32 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, reg, bufs, len, HZ);
- msleep(5); /* FIXME: magic number */
+ if (dev->wait_after_write)
+ msleep(dev->wait_after_write);
+
kfree(bufs);
return ret;
}
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
{
- return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+ int rc;
+
+ rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+
+ /* Stores GPO/GPIO values at the cache, if changed
+ Only write values should be stored, since input on a GPIO
+ register will return the input bits.
+ Not sure what happens on reading GPO register.
+ */
+ if (rc >= 0) {
+ if (reg == EM2880_R04_GPO)
+ dev->reg_gpo = buf[0];
+ else if (reg == EM28XX_R08_GPIO)
+ dev->reg_gpio = buf[0];
+ }
+
+ return rc;
}
/*
@@ -295,9 +194,20 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
{
int oldval;
u8 newval;
- if ((oldval = em28xx_read_reg(dev, reg)) < 0)
+
+ /* Uses cache for gpo/gpio registers */
+ if (reg == EM2880_R04_GPO)
+ oldval = dev->reg_gpo;
+ else if (reg == EM28XX_R08_GPIO)
+ oldval = dev->reg_gpio;
+ else
+ oldval = em28xx_read_reg(dev, reg);
+
+ if (oldval < 0)
return oldval;
+
newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+
return em28xx_write_regs(dev, reg, &newval, 1);
}
@@ -309,20 +219,26 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
{
int ret, i;
u8 addr = reg & 0x7f;
- if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
+
+ ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2);
+ if (ret < 0)
return ret;
- if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
+
+ ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+ if (ret < 0)
return ret;
/* Wait up to 50 ms for AC97 command to complete */
for (i = 0; i < 10; i++) {
- if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+ ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
+ if (ret < 0)
return ret;
+
if (!(ret & 0x01))
return 0;
msleep(5);
}
- em28xx_warn ("AC97 command still being executed: not handled properly!\n");
+ em28xx_warn("AC97 command still being executed: not handled properly!\n");
return 0;
}
@@ -340,7 +256,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
else
input = EM2800_AUDIO_SRC_TUNER;
- ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
+ ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
if (ret < 0)
return ret;
}
@@ -366,7 +282,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
}
}
- ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+ ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
if (ret < 0)
return ret;
msleep(5);
@@ -374,11 +290,11 @@ static int em28xx_set_audio_source(struct em28xx *dev)
/* Sets AC97 mixer registers
This is seems to be needed, even for non-ac97 configs
*/
- ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
+ ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video);
if (ret < 0)
return ret;
- ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
+ ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line);
return ret;
}
@@ -394,7 +310,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
/* Mute */
s[1] |= 0x80;
- ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+ ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
if (ret < 0)
return ret;
@@ -405,7 +321,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
if (!dev->mute)
xclk |= 0x80;
- ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
+ ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7);
if (ret < 0)
return ret;
msleep(10);
@@ -416,7 +332,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
/* Unmute device */
if (!dev->mute)
s[1] &= ~0x80;
- ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+ ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
return ret;
}
@@ -424,50 +340,68 @@ EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
int em28xx_colorlevels_set_default(struct em28xx *dev)
{
- em28xx_write_regs(dev, YGAIN_REG, "\x10", 1); /* contrast */
- em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1); /* brightness */
- em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1); /* saturation */
- em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1);
-
- em28xx_write_regs(dev, GAMMA_REG, "\x20", 1);
- em28xx_write_regs(dev, RGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, GGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, BGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1);
- return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */
+ em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1); /* brightness */
+ em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1); /* saturation */
+ em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1);
+
+ em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1);
+ return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1);
}
int em28xx_capture_start(struct em28xx *dev, int start)
{
- int ret;
+ int rc;
/* FIXME: which is the best order? */
/* video registers are sampled by VREF */
- if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
- 0x10)) < 0)
- return ret;
+ rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
+ start ? 0x10 : 0x00, 0x10);
+ if (rc < 0)
+ return rc;
+
+ if (!start) {
+ /* disable video capture */
+ rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1);
+ return rc;
+ }
+
/* enable video capture */
- return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
+ rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1);
+ else
+ rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1);
+
+ msleep(6);
+
+ return rc;
}
int em28xx_outfmt_set_yuv422(struct em28xx *dev)
{
- em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1);
- em28xx_write_regs(dev, VINMODE_REG, "\x10", 1);
- return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
+ em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1);
+ em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1);
+ return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1);
}
static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
u8 ymin, u8 ymax)
{
- em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
+ em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+ xmin, ymin, xmax, ymax);
- em28xx_write_regs(dev, XMIN_REG, &xmin, 1);
- em28xx_write_regs(dev, XMAX_REG, &xmax, 1);
- em28xx_write_regs(dev, YMIN_REG, &ymin, 1);
- return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
+ em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+ em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+ em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+ return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
}
static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
@@ -477,34 +411,36 @@ static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
u8 cheight = height;
u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
- em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7),
+ em28xx_coredbg("em28xx Area Set: (%d,%d)\n",
+ (width | (overflow & 2) << 7),
(height | (overflow & 1) << 8));
- em28xx_write_regs(dev, HSTART_REG, &hstart, 1);
- em28xx_write_regs(dev, VSTART_REG, &vstart, 1);
- em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1);
- em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1);
- return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
+ em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+ em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+ return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
}
static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
{
u8 mode;
/* the em2800 scaler only supports scaling down to 50% */
- if(dev->is_em2800)
+ if (dev->is_em2800)
mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
else {
u8 buf[2];
buf[0] = h;
buf[1] = h >> 8;
- em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2);
+ em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
buf[0] = v;
buf[1] = v >> 8;
- em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2);
- /* it seems that both H and V scalers must be active to work correctly */
+ em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+ /* it seems that both H and V scalers must be active
+ to work correctly */
mode = (h || v)? 0x30: 0x00;
}
- return em28xx_write_reg_bits(dev, COMPR_REG, mode, 0x30);
+ return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
}
/* FIXME: this only function read values from dev */
@@ -520,396 +456,280 @@ int em28xx_resolution_set(struct em28xx *dev)
return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
}
-
-/******************* isoc transfer handling ****************************/
-
-#ifdef ENABLE_DEBUG_ISOC_FRAMES
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs)
-#else
-static void em28xx_isoc_dump(struct urb *urb)
-#endif
+int em28xx_set_alternate(struct em28xx *dev)
{
- int len = 0;
- int ntrans = 0;
+ int errCode, prev_alt = dev->alt;
int i;
+ unsigned int min_pkt_size = dev->width * 2 + 4;
- printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n",
- urb->start_frame, urb->number_of_packets,
- urb->error_count);
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned char *buf =
- urb->transfer_buffer +
- urb->iso_frame_desc[i].offset;
- int alen = urb->iso_frame_desc[i].actual_length;
- if (alen > 0) {
- if (buf[0] == 0x88) {
- ntrans++;
- len += alen;
- } else if (buf[0] == 0x22) {
- printk(KERN_DEBUG
- "= l=%d nt=%d bpp=%d\n",
- len - 4 * ntrans, ntrans,
- ntrans == 0 ? 0 : len / ntrans);
- ntrans = 1;
- len = alen;
- } else
- printk(KERN_DEBUG "!\n");
+ /* When image size is bigger than a certain value,
+ the frame size should be increased, otherwise, only
+ green screen will be received.
+ */
+ if (dev->width * 2 * dev->height > 720 * 240 * 2)
+ min_pkt_size *= 2;
+
+ for (i = 0; i < dev->num_alt; i++) {
+ /* stop when the selected alt setting offers enough bandwidth */
+ if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
+ dev->alt = i;
+ break;
+ /* otherwise make sure that we end up with the maximum bandwidth
+ because the min_pkt_size equation might be wrong...
+ */
+ } else if (dev->alt_max_pkt_size[i] >
+ dev->alt_max_pkt_size[dev->alt])
+ dev->alt = i;
+ }
+
+ if (dev->alt != prev_alt) {
+ em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
+ min_pkt_size, dev->alt);
+ dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+ em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+ dev->alt, dev->max_pkt_size);
+ errCode = usb_set_interface(dev->udev, 0, dev->alt);
+ if (errCode < 0) {
+ em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+ dev->alt, errCode);
+ return errCode;
}
- printk(KERN_DEBUG " n=%d s=%d al=%d %x\n", i,
- urb->iso_frame_desc[i].status,
- urb->iso_frame_desc[i].actual_length,
- (unsigned int)
- *((unsigned char *)(urb->transfer_buffer +
- urb->iso_frame_desc[i].
- offset)));
}
+ return 0;
}
-#endif
-static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f,
- unsigned long *lock_flags, unsigned char buf)
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
{
- if (!(buf & 0x01)) {
- if ((*f)->state == F_GRABBING) {
- /*previous frame is incomplete */
- if ((*f)->fieldbytesused < dev->field_size) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)",
- dev->field_size-(*f)->fieldbytesused);
- } else {
- (*f)->state = F_DONE;
- (*f)->buf.bytesused = dev->frame_size;
- }
- }
- if ((*f)->state == F_DONE || (*f)->state == F_ERROR) {
- /* move current frame to outqueue and get next free buffer from inqueue */
- spin_lock_irqsave(&dev-> queue_lock, *lock_flags);
- list_move_tail(&(*f)->frame, &dev->outqueue);
- if (!list_empty(&dev->inqueue))
- (*f) = list_entry(dev-> inqueue.next,
- struct em28xx_frame_t,frame);
- else
- (*f) = NULL;
- spin_unlock_irqrestore(&dev->queue_lock,*lock_flags);
- }
- if (!(*f)) {
- em28xx_isocdbg ("new frame but no buffer is free");
- return -1;
- }
- do_gettimeofday(&(*f)->buf.timestamp);
- (*f)->buf.sequence = ++dev->frame_count;
- (*f)->buf.field = V4L2_FIELD_INTERLACED;
- (*f)->state = F_GRABBING;
- (*f)->buf.bytesused = 0;
- (*f)->top_field = 1;
- (*f)->fieldbytesused = 0;
- } else {
- /* acquiring bottom field */
- if ((*f)->state == F_GRABBING) {
- if (!(*f)->top_field) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("unexpected begin of bottom field; discarding it");
- } else if ((*f)-> fieldbytesused < dev->field_size - 172) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)",
- dev->field_size-(*f)->fieldbytesused);
- } else {
- (*f)->top_field = 0;
- (*f)->fieldbytesused = 0;
- }
+ int rc = 0;
+
+ if (!gpio)
+ return rc;
+
+ dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
+ else
+ dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
+ msleep(6);
+
+ /* Send GPIO reset sequences specified at board entry */
+ while (gpio->sleep >= 0) {
+ if (gpio->reg >= 0) {
+ rc = em28xx_write_reg_bits(dev,
+ gpio->reg,
+ gpio->val,
+ gpio->mask);
+ if (rc < 0)
+ return rc;
}
+ if (gpio->sleep > 0)
+ msleep(gpio->sleep);
+
+ gpio++;
}
- return (0);
+ return rc;
}
-static inline void em28xx_isoc_video_copy(struct em28xx *dev,
- struct em28xx_frame_t **f, unsigned char *buf, int len)
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
{
- void *fieldstart, *startwrite, *startread;
- int linesdone, currlinedone, offset, lencopy,remain;
+ if (dev->mode == set_mode)
+ return 0;
- if(dev->frame_size != (*f)->buf.length){
- em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
- return;
+ if (set_mode == EM28XX_MODE_UNDEFINED) {
+ dev->mode = set_mode;
+ return 0;
}
- if ((*f)->fieldbytesused + len > dev->field_size)
- len =dev->field_size - (*f)->fieldbytesused;
-
- if (buf[0] != 0x88 && buf[0] != 0x22) {
- em28xx_isocdbg("frame is not complete\n");
- startread = buf;
- len+=4;
- } else
- startread = buf + 4;
-
- remain = len;
+#if 0
+ /* Resource is locked */
+ if (dev->mode != EM28XX_MODE_UNDEFINED)
+ return -EINVAL;
+#endif
+ dev->mode = set_mode;
- if ((*f)->top_field)
- fieldstart = (*f)->bufmem;
+ if (dev->mode == EM28XX_DIGITAL_MODE)
+ return em28xx_gpio_set(dev, dev->digital_gpio);
else
- fieldstart = (*f)->bufmem + dev->bytesperline;
-
- linesdone = (*f)->fieldbytesused / dev->bytesperline;
- currlinedone = (*f)->fieldbytesused % dev->bytesperline;
- offset = linesdone * dev->bytesperline * 2 + currlinedone;
- startwrite = fieldstart + offset;
- lencopy = dev->bytesperline - currlinedone;
- lencopy = lencopy > remain ? remain : lencopy;
-
- memcpy(startwrite, startread, lencopy);
- remain -= lencopy;
-
- while (remain > 0) {
- startwrite += lencopy + dev->bytesperline;
- startread += lencopy;
- if (dev->bytesperline > remain)
- lencopy = remain;
- else
- lencopy = dev->bytesperline;
-
- memcpy(startwrite, startread, lencopy);
- remain -= lencopy;
- }
-
- (*f)->fieldbytesused += len;
+ return em28xx_gpio_set(dev, dev->analog_gpio);
}
+EXPORT_SYMBOL_GPL(em28xx_set_mode);
+
+/* ------------------------------------------------------------------
+ URB control
+ ------------------------------------------------------------------*/
/*
- * em28xx_isoIrq()
- * handles the incoming isoc urbs and fills the frames from our inqueue
+ * IRQ callback, called by URB callback
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void em28xx_irq_callback(struct urb *urb, struct pt_regs *regs)
#else
-static void em28xx_isocIrq(struct urb *urb)
+static void em28xx_irq_callback(struct urb *urb)
#endif
{
- struct em28xx *dev = urb->context;
- int i, status;
- struct em28xx_frame_t **f;
- unsigned long lock_flags;
-
- if (!dev)
- return;
-#ifdef ENABLE_DEBUG_ISOC_FRAMES
- if (isoc_debug>1)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
- em28xx_isoc_dump(urb, regs);
-#else
- em28xx_isoc_dump(urb);
-#endif
-#endif
-
- if (urb->status == -ENOENT)
- return;
-
- f = &dev->frame_current;
-
- if (dev->stream == STREAM_INTERRUPT) {
- dev->stream = STREAM_OFF;
- if ((*f))
- (*f)->state = F_QUEUED;
- em28xx_isocdbg("stream interrupted");
- wake_up_interruptible(&dev->wait_stream);
- }
-
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
- return;
-
- if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) {
- if (!(*f))
- (*f) = list_entry(dev->inqueue.next,
- struct em28xx_frame_t, frame);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned char *buf = urb->transfer_buffer +
- urb->iso_frame_desc[i].offset;
- int len = urb->iso_frame_desc[i].actual_length - 4;
-
- if (urb->iso_frame_desc[i].status) {
- em28xx_isocdbg("data error: [%d] len=%d, status=%d", i,
- urb->iso_frame_desc[i].actual_length,
- urb->iso_frame_desc[i].status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length <= 0) {
- em28xx_isocdbg("packet %d is empty",i);
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length >
- urb->iso_frame_desc[i].length) {
- em28xx_isocdbg("packet bigger than packet size");
- continue;
- }
- /*new frame */
- if (buf[0] == 0x22 && buf[1] == 0x5a) {
- em28xx_isocdbg("Video frame, length=%i!",len);
-
- if (em28xx_isoc_video(dev,f,&lock_flags,buf[2]))
- break;
- } else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) {
- em28xx_isocdbg("VBI HEADER!!!");
- }
+ struct em28xx_dmaqueue *dma_q = urb->context;
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ int rc, i;
- /* actual copying */
- if ((*f)->state == F_GRABBING) {
- em28xx_isoc_video_copy(dev,f,buf, len);
- }
- }
- }
+ /* Copy data from URB */
+ spin_lock(&dev->slock);
+ rc = dev->isoc_ctl.isoc_copy(dev, urb);
+ spin_unlock(&dev->slock);
+ /* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
-
urb->status = 0;
- if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
- em28xx_errdev("resubmit of urb failed (error=%i)\n", status);
- dev->state |= DEV_MISCONFIGURED;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ em28xx_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
}
- wake_up_interruptible(&dev->wait_frame);
- return;
}
/*
- * em28xx_uninit_isoc()
- * deallocates the buffers and urbs allocated during em28xx_init_iosc()
+ * Stop and Deallocate URBs
*/
void em28xx_uninit_isoc(struct em28xx *dev)
{
+ struct urb *urb;
int i;
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- if (dev->urb[i]) {
- usb_kill_urb(dev->urb[i]);
- if (dev->transfer_buffer[i]) {
+ em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+
+ dev->isoc_ctl.nfields = -1;
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = dev->isoc_ctl.urb[i];
+ if (urb) {
+ usb_kill_urb(urb);
+ usb_unlink_urb(urb);
+ if (dev->isoc_ctl.transfer_buffer[i]) {
usb_buffer_free(dev->udev,
- dev->urb[i]->transfer_buffer_length,
- dev->transfer_buffer[i],
- dev->urb[i]->transfer_dma);
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
}
- usb_free_urb(dev->urb[i]);
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[i] = NULL;
}
- dev->urb[i] = NULL;
- dev->transfer_buffer[i] = NULL;
+ dev->isoc_ctl.transfer_buffer[i] = NULL;
}
+
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
+
+ dev->isoc_ctl.urb = NULL;
+ dev->isoc_ctl.transfer_buffer = NULL;
+ dev->isoc_ctl.num_bufs = 0;
+
em28xx_capture_start(dev, 0);
}
+EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
/*
- * em28xx_init_isoc()
- * allocates transfer buffers and submits the urbs for isoc transfer
+ * Allocate URBs and start IRQ
*/
-int em28xx_init_isoc(struct em28xx *dev)
+int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
{
- /* change interface to 3 which allows the biggest packet sizes */
- int i, errCode;
- int sb_size;
-
- em28xx_set_alternate(dev);
- sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
-
- /* reset streaming vars */
- dev->frame_current = NULL;
- dev->frame_count = 0;
-
- /* allocate urbs */
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- struct urb *urb;
- int j;
- /* allocate transfer buffer */
- urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
- if (!urb){
- em28xx_errdev("cannot alloc urb %i\n", i);
+ struct em28xx_dmaqueue *dma_q = &dev->vidq;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int j, k;
+ int rc;
+
+ em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+
+ /* De-allocates all pending stuff */
+ em28xx_uninit_isoc(dev);
+
+ dev->isoc_ctl.isoc_copy = isoc_copy;
+ dev->isoc_ctl.num_bufs = num_bufs;
+
+ dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ em28xx_errdev("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+ GFP_KERNEL);
+ if (!dev->isoc_ctl.transfer_buffer) {
+ em28xx_errdev("cannot allocate memory for usbtransfer\n");
+ kfree(dev->isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.max_pkt_size = max_pkt_size;
+ dev->isoc_ctl.buf = NULL;
+
+ sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ if (!urb) {
+ em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
em28xx_uninit_isoc(dev);
return -ENOMEM;
}
- dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size,
- GFP_KERNEL,
- &urb->transfer_dma);
- if (!dev->transfer_buffer[i]) {
- em28xx_errdev
- ("unable to allocate %i bytes for transfer buffer %i\n",
- sb_size, i);
+ dev->isoc_ctl.urb[i] = urb;
+
+ dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+ if (!dev->isoc_ctl.transfer_buffer[i]) {
+ em28xx_err("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt()?" while in int":"");
em28xx_uninit_isoc(dev);
- usb_free_urb(urb);
return -ENOMEM;
}
- memset(dev->transfer_buffer[i], 0, sb_size);
- urb->dev = dev->udev;
- urb->context = dev;
- urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- urb->interval = 1;
- urb->transfer_buffer = dev->transfer_buffer[i];
- urb->complete = em28xx_isocIrq;
- urb->number_of_packets = EM28XX_NUM_PACKETS;
- urb->transfer_buffer_length = sb_size;
- for (j = 0; j < EM28XX_NUM_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = j * dev->max_pkt_size;
- urb->iso_frame_desc[j].length = dev->max_pkt_size;
+ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ /* FIXME: this is a hack - should be
+ 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
+ should also be using 'desc.bInterval'
+ */
+ pipe = usb_rcvisocpipe(dev->udev,
+ dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84);
+
+ usb_fill_int_urb(urb, dev->udev, pipe,
+ dev->isoc_ctl.transfer_buffer[i], sb_size,
+ em28xx_irq_callback, dma_q, 1);
+
+ urb->number_of_packets = max_packets;
+ urb->transfer_flags = URB_ISO_ASAP;
+
+ k = 0;
+ for (j = 0; j < max_packets; j++) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ dev->isoc_ctl.max_pkt_size;
+ k += dev->isoc_ctl.max_pkt_size;
}
- dev->urb[i] = urb;
}
- /* submit urbs */
- em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n",
- EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size);
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
- if (errCode) {
- em28xx_errdev("submit of urb %i failed (error=%i)\n", i,
- errCode);
- em28xx_uninit_isoc(dev);
- return errCode;
- }
- }
+ init_waitqueue_head(&dma_q->wq);
- return 0;
-}
+ em28xx_capture_start(dev, 1);
-int em28xx_set_alternate(struct em28xx *dev)
-{
- int errCode, prev_alt = dev->alt;
- int i;
- unsigned int min_pkt_size = dev->bytesperline + 4;
-
- /* When image size is bigger than a certain value,
- the frame size should be increased, otherwise, only
- green screen will be received.
- */
- if (dev->frame_size > 720*240*2)
- min_pkt_size *= 2;
-
- for (i = 0; i < dev->num_alt; i++) {
- /* stop when the selected alt setting offers enough bandwidth */
- if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
- dev->alt = i;
- break;
- /* otherwise make sure that we end up with the maximum bandwidth
- because the min_pkt_size equation might be wrong...
- */
- } else if (dev->alt_max_pkt_size[i] >
- dev->alt_max_pkt_size[dev->alt])
- dev->alt = i;
- }
-
- if (dev->alt != prev_alt) {
- em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
- min_pkt_size, dev->alt);
- dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
- em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
- dev->alt, dev->max_pkt_size);
- errCode = usb_set_interface(dev->udev, 0, dev->alt);
- if (errCode < 0) {
- em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
- dev->alt, errCode);
- return errCode;
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+ if (rc) {
+ em28xx_err("submit of urb %i failed (error=%i)\n", i,
+ rc);
+ em28xx_uninit_isoc(dev);
+ return rc;
}
}
+
return 0;
}
+EXPORT_SYMBOL_GPL(em28xx_init_isoc);
diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
new file mode 100644
index 000000000..c61c764e1
--- /dev/null
+++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c
@@ -0,0 +1,528 @@
+/*
+ DVB device driver for em28xx
+
+ (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
+ - Fixes for the driver to properly work with HVR-950
+ - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
+
+ (c) 2008 Aidan Thornton <makosoft@googlemail.com>
+
+ Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
+ (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include "compat.h"
+
+#include "em28xx.h"
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+
+#include "lgdt330x.h"
+#include "zl10353.h"
+#include "drx397xD.h"
+
+MODULE_DESCRIPTION("driver for em28xx based DVB cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level, fmt, arg...) do { \
+if (debug >= level) \
+ printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
+} while (0)
+
+#define EM28XX_DVB_NUM_BUFS 5
+#define EM28XX_DVB_MAX_PACKETSIZE 564
+#define EM28XX_DVB_MAX_PACKETS 64
+
+struct em28xx_dvb {
+ struct dvb_frontend *frontend;
+
+ /* feed count management */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex lock;
+#else
+ struct semaphore lock;
+#endif
+ int nfeeds;
+
+ /* general boilerplate stuff */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ struct dvb_adapter adapter;
+#else
+ struct dvb_adapter *adapter;
+#endif
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net net;
+};
+
+
+static inline void print_err_status(struct em28xx *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ dprintk(1, "URB status %d [%s].\n", status, errmsg);
+ } else {
+ dprintk(1, "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+ int i;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
+
+ return 0;
+}
+
+static int start_streaming(struct em28xx_dvb *dvb)
+{
+ int rc;
+ struct em28xx *dev = dvb->adapter.priv;
+
+ usb_set_interface(dev->udev, 0, 1);
+ rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ if (rc < 0)
+ return rc;
+
+ return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
+ EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
+ dvb_isoc_copy);
+}
+
+static int stop_streaming(struct em28xx_dvb *dvb)
+{
+ struct em28xx *dev = dvb->adapter.priv;
+
+ em28xx_uninit_isoc(dev);
+
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+
+ return 0;
+}
+
+static int start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct em28xx_dvb *dvb = demux->priv;
+ int rc, ret;
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds++;
+ rc = dvb->nfeeds;
+
+ if (dvb->nfeeds == 1) {
+ ret = start_streaming(dvb);
+ if (ret < 0)
+ rc = ret;
+ }
+
+ mutex_unlock(&dvb->lock);
+ return rc;
+}
+
+static int stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct em28xx_dvb *dvb = demux->priv;
+ int err = 0;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds--;
+
+ if (0 == dvb->nfeeds)
+ err = stop_streaming(dvb);
+
+ mutex_unlock(&dvb->lock);
+ return err;
+}
+
+
+
+/* ------------------------------------------------------------------ */
+static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct em28xx *dev = fe->dvb->priv;
+
+ if (acquire)
+ return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ else
+ return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct lgdt330x_config em2880_lgdt3303_dev = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+};
+
+static struct zl10353_config em28xx_zl10353_with_xc3028 = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .if2 = 45600,
+};
+
+#ifdef EM28XX_DRX397XD_SUPPORT
+/* [TODO] djh - not sure yet what the device config needs to contain */
+static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
+ .demod_address = (0xe0 >> 1),
+};
+#endif
+
+/* ------------------------------------------------------------------ */
+
+static int attach_xc3028(u8 addr, struct em28xx *dev)
+{
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.i2c_adap = &dev->i2c_adap;
+ cfg.i2c_addr = addr;
+ cfg.callback = em28xx_tuner_callback;
+
+ if (!dev->dvb->frontend) {
+ printk(KERN_ERR "%s/2: dvb frontend not attached. "
+ "Can't attach xc3028\n",
+ dev->name);
+ return -EINVAL;
+ }
+
+ fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+ dev->name);
+ dvb_frontend_detach(dev->dvb->frontend);
+ dev->dvb->frontend = NULL;
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int register_dvb(struct em28xx_dvb *dvb,
+ struct module *module,
+ struct em28xx *dev,
+ struct device *device)
+{
+ int result;
+
+ mutex_init(&dvb->lock);
+
+ /* register adapter */
+ result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
+ adapter_nr);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_adapter;
+ }
+
+ /* Ensure all frontends negotiate bus access */
+ dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+#else
+ dvb->adapter->priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(dvb->adapter, dvb->frontend);
+#endif
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dvb;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = start_feed;
+ dvb->demux.stop_feed = stop_feed;
+
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+#else
+ result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
+#endif
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#else
+ dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#endif
+ return 0;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_unregister_adapter(&dvb->adapter);
+#else
+ dvb_unregister_adapter(dvb->adapter);
+#endif
+fail_adapter:
+ return result;
+}
+
+static void unregister_dvb(struct em28xx_dvb *dvb)
+{
+ dvb_net_release(&dvb->net);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_unregister_adapter(&dvb->adapter);
+#else
+ dvb_unregister_adapter(dvb->adapter);
+#endif
+}
+
+
+static int dvb_init(struct em28xx *dev)
+{
+ int result = 0;
+ struct em28xx_dvb *dvb;
+
+ dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
+
+ if (dvb == NULL) {
+ printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
+ return -ENOMEM;
+ }
+ dev->dvb = dvb;
+
+ em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ /* init frontend */
+ switch (dev->model) {
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+ dvb->frontend = dvb_attach(lgdt330x_attach,
+ &em2880_lgdt3303_dev,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ dvb->frontend = dvb_attach(zl10353_attach,
+ &em28xx_zl10353_with_xc3028,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+#ifdef EM28XX_DRX397XD_SUPPORT
+ /* We don't have the config structure properly populated, so
+ this is commented out for now */
+ dvb->frontend = dvb_attach(drx397xD_attach,
+ &em28xx_drx397xD_with_xc3028,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+#endif
+ default:
+ printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
+ " isn't supported yet\n",
+ dev->name);
+ break;
+ }
+ if (NULL == dvb->frontend) {
+ printk(KERN_ERR
+ "%s/2: frontend initialization failed\n",
+ dev->name);
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* register everything */
+ result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+
+ if (result < 0)
+ goto out_free;
+
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
+ return 0;
+
+out_free:
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ kfree(dvb);
+ dev->dvb = NULL;
+ return result;
+}
+
+static int dvb_fini(struct em28xx *dev)
+{
+ if (dev->dvb) {
+ unregister_dvb(dev->dvb);
+ dev->dvb = NULL;
+ }
+
+ return 0;
+}
+
+static struct em28xx_ops dvb_ops = {
+ .id = EM28XX_DVB,
+ .name = "Em28xx dvb Extension",
+ .init = dvb_init,
+ .fini = dvb_fini,
+};
+
+static int __init em28xx_dvb_register(void)
+{
+ return em28xx_register_extension(&dvb_ops);
+}
+
+static void __exit em28xx_dvb_unregister(void)
+{
+ em28xx_unregister_extension(&dvb_ops);
+}
+
+module_init(em28xx_dvb_register);
+module_exit(em28xx_dvb_unregister);
diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index e13743d67..c22e73019 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -41,11 +41,21 @@ static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
- printk(fmt, ##args); } while (0)
-#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
- printk(KERN_DEBUG "%s at %s: " fmt, \
- dev->name, __FUNCTION__ , ##args); } while (0)
+
+#define dprintk1(lvl, fmt, args...) \
+do { \
+ if (i2c_debug >= lvl) { \
+ printk(fmt, ##args); \
+ } \
+} while (0)
+
+#define dprintk2(lvl, fmt, args...) \
+do { \
+ if (i2c_debug >= lvl) { \
+ printk(KERN_DEBUG "%s at %s: " fmt, \
+ dev->name, __func__ , ##args); \
+ } \
+} while (0)
/*
* em2800_i2c_send_max4()
@@ -235,16 +245,16 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
return 0;
for (i = 0; i < num; i++) {
addr = msgs[i].addr << 1;
- dprintk2(2,"%s %s addr=%x len=%d:",
+ dprintk2(2, "%s %s addr=%x len=%d:",
(msgs[i].flags & I2C_M_RD) ? "read" : "write",
i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
- if (!msgs[i].len) { /* no len: check only for device presence */
+ if (!msgs[i].len) { /* no len: check only for device presence */
if (dev->is_em2800)
rc = em2800_i2c_check_for_device(dev, addr);
else
rc = em28xx_i2c_check_for_device(dev, addr);
if (rc < 0) {
- dprintk2(2," no device\n");
+ dprintk2(2, " no device\n");
return rc;
}
@@ -258,14 +268,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = em28xx_i2c_recv_bytes(dev, addr,
msgs[i].buf,
msgs[i].len);
- if (i2c_debug>=2) {
- for (byte = 0; byte < msgs[i].len; byte++) {
+ if (i2c_debug >= 2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
- }
}
} else {
/* write bytes */
- if (i2c_debug>=2) {
+ if (i2c_debug >= 2) {
for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
}
@@ -281,13 +290,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
}
if (rc < 0)
goto err;
- if (i2c_debug>=2)
+ if (i2c_debug >= 2)
printk("\n");
}
return num;
- err:
- dprintk2(2," ERROR: %i\n", rc);
+err:
+ dprintk2(2, " ERROR: %i\n", rc);
return rc;
}
@@ -330,7 +339,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
return -1;
buf = 0;
- if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
+
+ err = i2c_master_send(&dev->i2c_client, &buf, 1);
+ if (err != 1) {
printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
dev->name, err);
return -1;
@@ -403,8 +414,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
break;
}
printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
- em_eeprom->string_idx_table,em_eeprom->string1,
- em_eeprom->string2,em_eeprom->string3);
+ em_eeprom->string_idx_table,
+ em_eeprom->string1,
+ em_eeprom->string2,
+ em_eeprom->string3);
return 0;
}
@@ -441,58 +454,61 @@ static int attach_inform(struct i2c_client *client)
struct em28xx *dev = client->adapter->algo_data;
switch (client->addr << 1) {
- case 0x86:
- case 0x84:
- case 0x96:
- case 0x94:
- {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- struct tuner_setup tun_setup;
-
- tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
- tun_setup.type = TUNER_TDA9887;
- tun_setup.addr = client->addr;
-
- em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
- em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
- &tda9887_cfg);
- break;
- }
- case 0x42:
- dprintk1(1,"attach_inform: saa7114 detected.\n");
- break;
- case 0x4a:
- dprintk1(1,"attach_inform: saa7113 detected.\n");
- break;
- case 0xa0:
- dprintk1(1,"attach_inform: eeprom detected.\n");
- break;
- case 0x60:
- case 0x8e:
- {
- struct IR_i2c *ir = i2c_get_clientdata(client);
- dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
- em28xx_set_ir(dev,ir);
- break;
- }
- case 0x80:
- case 0x88:
- dprintk1(1,"attach_inform: msp34xx detected.\n");
- break;
- case 0xb8:
- case 0xba:
- dprintk1(1,"attach_inform: tvp5150 detected.\n");
- break;
+ case 0x86:
+ case 0x84:
+ case 0x96:
+ case 0x94:
+ {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = TUNER_TDA9887;
+ tun_setup.addr = client->addr;
+
+ em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR,
+ &tun_setup);
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+ em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
+ &tda9887_cfg);
+ break;
+ }
+ case 0x42:
+ dprintk1(1, "attach_inform: saa7114 detected.\n");
+ break;
+ case 0x4a:
+ dprintk1(1, "attach_inform: saa7113 detected.\n");
+ break;
+ case 0xa0:
+ dprintk1(1, "attach_inform: eeprom detected.\n");
+ break;
+ case 0x60:
+ case 0x8e:
+ {
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+ dprintk1(1, "attach_inform: IR detected (%s).\n",
+ ir->phys);
+ em28xx_set_ir(dev, ir);
+ break;
+ }
+ case 0x80:
+ case 0x88:
+ dprintk1(1, "attach_inform: msp34xx detected.\n");
+ break;
+ case 0xb8:
+ case 0xba:
+ dprintk1(1, "attach_inform: tvp5150 detected.\n");
+ break;
- default:
- if (!dev->tuner_addr)
- dev->tuner_addr = client->addr;
+ default:
+ if (!dev->tuner_addr)
+ dev->tuner_addr = client->addr;
- dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+ dprintk1(1, "attach inform: detected I2C address %x\n",
+ client->addr << 1);
}
@@ -522,7 +538,7 @@ static struct i2c_adapter em28xx_adap_template = {
static struct i2c_client em28xx_client_template = {
.name = "em28xx internal",
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
.flags = I2C_CLIENT_ALLOW_USE,
#endif
};
diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c
index 5c78eceff..49c40f083 100644
--- a/linux/drivers/media/video/em28xx/em28xx-input.c
+++ b/linux/drivers/media/video/em28xx/em28xx-input.c
@@ -33,10 +33,12 @@
static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
-#define dprintk(fmt, arg...) if (ir_debug) \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+#define dprintk(fmt, arg...) \
+ if (ir_debug) { \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+ }
/* ----------------------------------------------------------------------- */
@@ -45,7 +47,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(&ir->c,&b,1)) {
+ if (1 != i2c_master_recv(&ir->c, &b, 1)) {
dprintk("read error\n");
return -EIO;
}
@@ -75,29 +77,30 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char code;
/* poll IR chip */
- if (2 != i2c_master_recv(&ir->c,buf,2))
+ if (2 != i2c_master_recv(&ir->c, buf, 2))
return -EIO;
/* Does eliminate repeated parity code */
- if (buf[1]==0xff)
+ if (buf[1] == 0xff)
return 0;
#if 0
/* avoid reapeating keystrokes */
- if (buf[1]==ir->old)
+ if (buf[1] == ir->old)
return 0;
#endif
- ir->old=buf[1];
+ ir->old = buf[1];
/* Rearranges bits to the right order */
- code= ((buf[0]&0x01)<<5) | /* 0010 0000 */
+ code = ((buf[0]&0x01)<<5) | /* 0010 0000 */
((buf[0]&0x02)<<3) | /* 0001 0000 */
((buf[0]&0x04)<<1) | /* 0000 1000 */
((buf[0]&0x08)>>1) | /* 0000 0100 */
((buf[0]&0x10)>>3) | /* 0000 0010 */
((buf[0]&0x20)>>5); /* 0000 0001 */
- dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]);
+ dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
+ code, buf[0]);
/* return key */
*ir_key = code;
@@ -112,15 +115,14 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
/* poll IR chip */
- if (3 != i2c_master_recv(&ir->c,buf,3)) {
+ if (3 != i2c_master_recv(&ir->c, buf, 3)) {
dprintk("read error\n");
return -EIO;
}
dprintk("key %02x\n", buf[2]&0x3f);
- if (buf[0]!=0x00){
+ if (buf[0] != 0x00)
return 0;
- }
*ir_key = buf[2]&0x3f;
*ir_raw = buf[2]&0x3f;
diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h
new file mode 100644
index 000000000..9058bed07
--- /dev/null
+++ b/linux/drivers/media/video/em28xx/em28xx-reg.h
@@ -0,0 +1,88 @@
+#define EM_GPIO_0 (1 << 0)
+#define EM_GPIO_1 (1 << 1)
+#define EM_GPIO_2 (1 << 2)
+#define EM_GPIO_3 (1 << 3)
+#define EM_GPIO_4 (1 << 4)
+#define EM_GPIO_5 (1 << 5)
+#define EM_GPIO_6 (1 << 6)
+#define EM_GPIO_7 (1 << 7)
+
+#define EM_GPO_0 (1 << 0)
+#define EM_GPO_1 (1 << 1)
+#define EM_GPO_2 (1 << 2)
+#define EM_GPO_3 (1 << 3)
+
+/* em2800 registers */
+#define EM2800_R08_AUDIOSRC 0x08
+
+/* em28xx registers */
+
+ /* GPIO/GPO registers */
+#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
+#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */
+
+#define EM28XX_R06_I2C_CLK 0x06
+#define EM28XX_R0A_CHIPID 0x0a
+#define EM28XX_R0C_USBSUSP 0x0c /* */
+
+#define EM28XX_R0E_AUDIOSRC 0x0e
+#define EM28XX_R0F_XCLK 0x0f
+
+#define EM28XX_R10_VINMODE 0x10
+#define EM28XX_R11_VINCTRL 0x11
+#define EM28XX_R12_VINENABLE 0x12 /* */
+
+#define EM28XX_R14_GAMMA 0x14
+#define EM28XX_R15_RGAIN 0x15
+#define EM28XX_R16_GGAIN 0x16
+#define EM28XX_R17_BGAIN 0x17
+#define EM28XX_R18_ROFFSET 0x18
+#define EM28XX_R19_GOFFSET 0x19
+#define EM28XX_R1A_BOFFSET 0x1a
+
+#define EM28XX_R1B_OFLOW 0x1b
+#define EM28XX_R1C_HSTART 0x1c
+#define EM28XX_R1D_VSTART 0x1d
+#define EM28XX_R1E_CWIDTH 0x1e
+#define EM28XX_R1F_CHEIGHT 0x1f
+
+#define EM28XX_R20_YGAIN 0x20
+#define EM28XX_R21_YOFFSET 0x21
+#define EM28XX_R22_UVGAIN 0x22
+#define EM28XX_R23_UOFFSET 0x23
+#define EM28XX_R24_VOFFSET 0x24
+#define EM28XX_R25_SHARPNESS 0x25
+
+#define EM28XX_R26_COMPR 0x26
+#define EM28XX_R27_OUTFMT 0x27
+
+#define EM28XX_R28_XMIN 0x28
+#define EM28XX_R29_XMAX 0x29
+#define EM28XX_R2A_YMIN 0x2a
+#define EM28XX_R2B_YMAX 0x2b
+
+#define EM28XX_R30_HSCALELOW 0x30
+#define EM28XX_R31_HSCALEHIGH 0x31
+#define EM28XX_R32_VSCALELOW 0x32
+#define EM28XX_R33_VSCALEHIGH 0x33
+
+#define EM28XX_R40_AC97LSB 0x40
+#define EM28XX_R41_AC97MSB 0x41
+#define EM28XX_R42_AC97ADDR 0x42
+#define EM28XX_R43_AC97BUSY 0x43
+
+/* em202 registers */
+#define EM28XX_R02_MASTER_AC97 0x02
+#define EM28XX_R10_LINE_IN_AC97 0x10
+#define EM28XX_R14_VIDEO_AC97 0x14
+
+/* register settings */
+#define EM2800_AUDIO_SRC_TUNER 0x0d
+#define EM2800_AUDIO_SRC_LINE 0x0c
+#define EM28XX_AUDIO_SRC_TUNER 0xc0
+#define EM28XX_AUDIO_SRC_LINE 0x80
+
+/* FIXME: Need to be populated with the other chip ID's */
+enum em28xx_chip_id {
+ CHIP_ID_EM2883 = 36,
+};
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 4999897ed..546d776ab 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -1,5 +1,6 @@
/*
- em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+ em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+ video capture devices
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
@@ -33,7 +34,7 @@
#include <linux/i2c.h>
#include <linux/version.h>
#include <linux/mm.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
#include <linux/mutex.h>
#endif
@@ -41,7 +42,7 @@
#include <media/v4l2-common.h>
#include <media/msp3400.h>
#include <media/tuner.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
#include "i2c-compat.h"
#endif
@@ -57,7 +58,19 @@
#define em28xx_videodbg(fmt, arg...) do {\
if (video_debug) \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) \
+do {\
+ if (isoc_debug) { \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); \
+ } \
+ } while (0)
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -70,13 +83,13 @@ static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
MODULE_PARM(card, "1-" __stringify(EM28XX_MAXBOARDS) "i");
MODULE_PARM(video_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
MODULE_PARM(vbi_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
MODULE_PARM(radio_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
static int dummy;
module_param_array(card, int, dummy, 0444);
module_param_array(video_nr, int, dummy, 0444);
@@ -95,8 +108,8 @@ MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
static unsigned int video_debug;
-module_param(video_debug,int,0644);
-MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
static unsigned long em28xx_devused;
@@ -113,7 +126,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
.step = 0x1,
.default_value = 0x1f,
.flags = 0,
- },{
+ }, {
.id = V4L2_CID_AUDIO_MUTE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Mute",
@@ -127,8 +140,395 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
static struct usb_driver em28xx_usb_driver;
+/* ------------------------------------------------------------------
+ DMA and thread functions
+ ------------------------------------------------------------------*/
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void em28xx_copy_video(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ void *fieldstart, *startwrite, *startread;
+ int linesdone, currlinedone, offset, lencopy, remain;
+ int bytesperline = dev->width << 1;
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ if (p[0] != 0x88 && p[0] != 0x22) {
+ em28xx_isocdbg("frame is not complete\n");
+ len += 4;
+ } else
+ p += 4;
+
+ startread = p;
+ remain = len;
+
+ /* Interlaces frame */
+ if (buf->top_field)
+ fieldstart = outp;
+ else
+ fieldstart = outp + bytesperline;
+
+ linesdone = dma_q->pos / bytesperline;
+ currlinedone = dma_q->pos % bytesperline;
+ offset = linesdone * bytesperline * 2 + currlinedone;
+ startwrite = fieldstart + offset;
+ lencopy = bytesperline - currlinedone;
+ lencopy = lencopy > remain ? remain : lencopy;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ return;
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+
+ while (remain > 0) {
+ startwrite += lencopy + bytesperline;
+ startread += lencopy;
+ if (bytesperline > remain)
+ lencopy = remain;
+ else
+ lencopy = bytesperline;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size -
+ (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ break;
+
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+ }
+
+ dma_q->pos += len;
+}
+
+static inline void print_err_status(struct em28xx *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
+ } else {
+ em28xx_isocdbg("URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
-/********************* v4l2 interface ******************************************/
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer **buf)
+{
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+#if 1
+ char *outp;
+#endif
+
+ if (list_empty(&dma_q->active)) {
+ em28xx_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+
+#if 1
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0, (*buf)->vb.size);
+#endif
+
+ dev->isoc_ctl.buf = *buf;
+
+ return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+ struct em28xx_buffer *buf;
+ struct em28xx_dmaqueue *dma_q = urb->context;
+ unsigned char *outp = NULL;
+ int i, len = 0, rc = 1;
+ unsigned char *p;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->isoc_ctl.buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ len = urb->iso_frame_desc[i].actual_length - 4;
+
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ /* em28xx_isocdbg("packet %d is empty",i); - spammy */
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ /* FIXME: incomplete buffer checks where removed to make
+ logic simpler. Impacts of those changes should be evaluated
+ */
+ if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
+ em28xx_isocdbg("VBI HEADER!!!\n");
+ /* FIXME: Should add vbi copy */
+ continue;
+ }
+ if (p[0] == 0x22 && p[1] == 0x5a) {
+ em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+ len, (p[2] & 1)? "odd" : "even");
+
+ if (!(p[2] & 1)) {
+ if (buf != NULL)
+ buffer_filled(dev, dma_q, buf);
+ get_next_buf(dma_q, &buf);
+ if (buf == NULL)
+ outp = NULL;
+ else
+ outp = videobuf_to_vmalloc(&buf->vb);
+ }
+
+ if (buf != NULL) {
+ if (p[2] & 1)
+ buf->top_field = 0;
+ else
+ buf->top_field = 1;
+ }
+
+ dma_q->pos = 0;
+ }
+ if (buf != NULL)
+ em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+ }
+ return rc;
+}
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct v4l2_frequency f;
+
+ *size = 16 * fh->dev->width * fh->dev->height >> 3;
+ if (0 == *count)
+ *count = EM28XX_DEF_BUF;
+
+ if (*count < EM28XX_MIN_BUF)
+ *count = EM28XX_MIN_BUF;
+
+ /* Ask tuner to go to analog mode */
+ memset(&f, 0, sizeof(f));
+ f.frequency = dev->ctl_freq;
+
+ em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.buf == buf)
+ dev->isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ /* FIXME: It assumes depth = 16 */
+ /* The only currently supported format is 16 bits/pixel */
+ buf->vb.size = 16 * dev->width * dev->height >> 3;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ if (!dev->isoc_ctl.num_bufs)
+ urb_init = 1;
+
+ if (urb_init) {
+ rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+ EM28XX_NUM_BUFS, dev->max_pkt_size,
+ em28xx_isoc_copy);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_dmaqueue *vidq = &dev->vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = (struct em28xx *)fh->dev;
+
+ em28xx_isocdbg("em28xx: called buffer_release\n");
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops em28xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************* v4l2 interface **************************************/
/*
* em28xx_config()
@@ -144,9 +544,9 @@ static int em28xx_config(struct em28xx *dev)
#if 1
/* enable vbi capturing */
-/* em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
-/* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
- em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+/* em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */
+/* em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */
+ em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1);
#endif
dev->mute = 1; /* maybe not the right place... */
@@ -174,23 +574,6 @@ static void em28xx_config_i2c(struct em28xx *dev)
em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
}
-/*
- * em28xx_empty_framequeues()
- * prepare queues for incoming and outgoing frames
- */
-static void em28xx_empty_framequeues(struct em28xx *dev)
-{
- u32 i;
-
- INIT_LIST_HEAD(&dev->inqueue);
- INIT_LIST_HEAD(&dev->outqueue);
-
- for (i = 0; i < EM28XX_NUM_FRAMES; i++) {
- dev->frame[i].state = F_UNUSED;
- dev->frame[i].buf.bytesused = 0;
- }
-}
-
static void video_mux(struct em28xx *dev, int index)
{
struct v4l2_routing route;
@@ -203,12 +586,15 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
if (dev->has_msp34xx) {
- if (dev->i2s_speed)
- em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
+ if (dev->i2s_speed) {
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ,
+ &dev->i2s_speed);
+ }
route.input = dev->ctl_ainput;
route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
/* Note: this is msp3400 specific */
- em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
+ &route);
}
em28xx_audio_analog_set(dev);
@@ -224,15 +610,12 @@ static int res_get(struct em28xx_fh *fh)
if (fh->stream_on)
return rc;
- mutex_lock(&dev->lock);
-
if (dev->stream_on)
- rc = -EINVAL;
- else {
- dev->stream_on = 1;
- fh->stream_on = 1;
- }
+ return -EINVAL;
+ mutex_lock(&dev->lock);
+ dev->stream_on = 1;
+ fh->stream_on = 1;
mutex_unlock(&dev->lock);
return rc;
}
@@ -253,33 +636,6 @@ static void res_free(struct em28xx_fh *fh)
}
/*
- * em28xx_vm_open()
- */
-static void em28xx_vm_open(struct vm_area_struct *vma)
-{
- struct em28xx_frame_t *f = vma->vm_private_data;
- f->vma_use_count++;
-}
-
-/*
- * em28xx_vm_close()
- */
-static void em28xx_vm_close(struct vm_area_struct *vma)
-{
- /* NOTE: buffers are not freed here */
- struct em28xx_frame_t *f = vma->vm_private_data;
-
- if (f->vma_use_count)
- f->vma_use_count--;
-}
-
-static struct vm_operations_struct em28xx_vm_ops = {
- .open = em28xx_vm_open,
- .close = em28xx_vm_close,
-};
-
-
-/*
* em28xx_get_ctrl()
* return the current saturation, brightness or contrast, mute state
*/
@@ -318,34 +674,6 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
}
}
-/*
- * em28xx_stream_interrupt()
- * stops streaming
- */
-static int em28xx_stream_interrupt(struct em28xx *dev)
-{
- int rc = 0;
-
- /* stop reading from the device */
-
- dev->stream = STREAM_INTERRUPT;
- rc = wait_event_timeout(dev->wait_stream,
- (dev->stream == STREAM_OFF) ||
- (dev->state & DEV_DISCONNECTED),
- EM28XX_URB_TIMEOUT);
-
- if (rc) {
- dev->state |= DEV_MISCONFIGURED;
- em28xx_videodbg("device is misconfigured; close and "
- "open /dev/video%d again\n",
- dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
- return rc;
- }
-
- return 0;
-}
-
-
static int check_dev(struct em28xx *dev)
{
if (dev->state & DEV_DISCONNECTED) {
@@ -381,7 +709,7 @@ static void get_scale(struct em28xx *dev,
IOCTL vidioc handling
------------------------------------------------------------------*/
-static int vidioc_g_fmt_cap(struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct em28xx_fh *fh = priv;
@@ -392,8 +720,8 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- f->fmt.pix.bytesperline = dev->bytesperline;
- f->fmt.pix.sizeimage = dev->frame_size;
+ f->fmt.pix.bytesperline = dev->width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
@@ -404,7 +732,7 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_try_fmt_cap(struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct em28xx_fh *fh = priv;
@@ -464,64 +792,49 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc, i;
+ int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- vidioc_try_fmt_cap(file, priv, f);
+ vidioc_try_fmt_vid_cap(file, priv, f);
mutex_lock(&dev->lock);
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].vma_use_count) {
- em28xx_videodbg("VIDIOC_S_FMT failed. "
- "Unmap the buffers first.\n");
- rc = -EINVAL;
- goto err;
- }
-
- /* stop io in case it is already in progress */
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0)
- goto err;
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ em28xx_errdev("%s queue busy\n", __func__);
+ rc = -EBUSY;
+ goto out;
}
- em28xx_release_buffers(dev);
- dev->io = IO_NONE;
+ if (dev->stream_on && !fh->stream_on) {
+ em28xx_errdev("%s device in use by another fh\n", __func__);
+ rc = -EBUSY;
+ goto out;
+ }
/* set new image size */
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1;
- dev->bytesperline = dev->width * 2;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
- /* FIXME: This is really weird! Why capture is starting with
- this ioctl ???
- */
- em28xx_uninit_isoc(dev);
em28xx_set_alternate(dev);
- em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev);
- em28xx_init_isoc(dev);
+
rc = 0;
-err:
+out:
mutex_unlock(&dev->lock);
return rc;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
@@ -539,16 +852,13 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
/* Adjusts width/height, if needed */
f.fmt.pix.width = dev->width;
f.fmt.pix.height = dev->height;
- vidioc_try_fmt_cap(file, priv, &f);
+ vidioc_try_fmt_vid_cap(file, priv, &f);
mutex_lock(&dev->lock);
/* set new image size */
dev->width = f.fmt.pix.width;
dev->height = f.fmt.pix.height;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1;
- dev->bytesperline = dev->width * 2;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_resolution_set(dev);
@@ -641,11 +951,11 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
index = dev->ctl_ainput;
- if (index == 0) {
+ if (index == 0)
strcpy(a->name, "Television");
- } else {
+ else
strcpy(a->name, "Line In");
- }
+
a->capability = V4L2_AUDCAP_STEREO;
a->index = index;
@@ -856,9 +1166,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
static int em28xx_reg_len(int reg)
{
switch (reg) {
- case AC97LSB_REG:
- case HSCALELOW_REG:
- case VSCALELOW_REG:
+ case EM28XX_R40_AC97LSB:
+ case EM28XX_R30_HSCALELOW:
+ case EM28XX_R32_VSCALELOW:
return 2;
default:
return 1;
@@ -882,13 +1192,13 @@ static int vidioc_g_register(struct file *file, void *priv,
reg->val = ret;
} else {
- u64 val = 0;
+ __le64 val = 0;
ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
reg->reg, (char *)&val, 2);
if (ret < 0)
return ret;
- reg->val = cpu_to_le64((__u64)val);
+ reg->val = le64_to_cpu(val);
}
return 0;
@@ -899,9 +1209,9 @@ static int vidioc_s_register(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- u64 buf;
+ __le64 buf;
- buf = le64_to_cpu((__u64)reg->val);
+ buf = cpu_to_le64(reg->val);
return em28xx_write_regs(dev, reg->reg, (char *)&buf,
em28xx_reg_len(reg->reg));
@@ -940,23 +1250,11 @@ static int vidioc_streamon(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&dev->inqueue))
- return -EINVAL;
-
- mutex_lock(&dev->lock);
- if (unlikely(res_get(fh) < 0)) {
- mutex_unlock(&dev->lock);
+ if (unlikely(res_get(fh) < 0))
return -EBUSY;
- }
- dev->stream = STREAM_ON; /* FIXME: Start video capture here? */
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_streamon(&fh->vb_vidq));
}
static int vidioc_streamoff(struct file *file, void *priv,
@@ -970,23 +1268,14 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (type != fh->type)
return -EINVAL;
- mutex_lock(&dev->lock);
-
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0) {
- mutex_unlock(&dev->lock);
- return rc;
- }
- }
-
- em28xx_empty_framequeues(dev);
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1017,7 +1306,7 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_fmt_cap(struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *fmtd)
{
if (fmtd->index != 0)
@@ -1032,7 +1321,7 @@ static int vidioc_enum_fmt_cap(struct file *file, void *priv,
}
/* Sliced VBI ioctls */
-static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
+static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct em28xx_fh *fh = priv;
@@ -1056,7 +1345,7 @@ static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
return rc;
}
-static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
+static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct em28xx_fh *fh = priv;
@@ -1080,7 +1369,7 @@ static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
#if 0
/* RAW VBI ioctls */
-static int vidioc_g_fmt_vbi(struct file *file, void *priv,
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
format->fmt.vbi.sampling_rate = 6750000 * 4;
@@ -1096,7 +1385,7 @@ static int vidioc_g_fmt_vbi(struct file *file, void *priv,
return 0;
}
-static int vidioc_try_set_vbi(struct file *file, void *priv,
+static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
format->type = V4L2_BUF_TYPE_VBI_CAPTURE;
@@ -1117,53 +1406,13 @@ static int vidioc_reqbufs(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- u32 i;
int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- rb->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (dev->io == IO_READ) {
- em28xx_videodbg("method is set to read;"
- " close and open the device again to"
- " choose the mmap I/O method\n");
- return -EINVAL;
- }
-
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].vma_use_count) {
- em28xx_videodbg("VIDIOC_REQBUFS failed; "
- "previous buffers are still mapped\n");
- return -EINVAL;
- }
-
- mutex_lock(&dev->lock);
-
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0) {
- mutex_unlock(&dev->lock);
- return rc;
- }
- }
-
- em28xx_empty_framequeues(dev);
-
- em28xx_release_buffers(dev);
- if (rb->count)
- rb->count = em28xx_request_buffers(dev, rb->count);
-
- dev->frame_current = NULL;
- dev->io = rb->count ? IO_MMAP : IO_NONE;
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_reqbufs(&fh->vb_vidq, rb));
}
static int vidioc_querybuf(struct file *file, void *priv,
@@ -1177,52 +1426,20 @@ static int vidioc_querybuf(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b->index >= dev->num_frames || dev->io != IO_MMAP)
- return -EINVAL;
-
- mutex_lock(&dev->lock);
-
- memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
-
- if (dev->frame[b->index].vma_use_count)
- b->flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (dev->frame[b->index].state == F_DONE)
- b->flags |= V4L2_BUF_FLAG_DONE;
- else if (dev->frame[b->index].state != F_UNUSED)
- b->flags |= V4L2_BUF_FLAG_QUEUED;
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_querybuf(&fh->vb_vidq, b));
}
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- unsigned long lock_flags;
int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP ||
- b->index >= dev->num_frames)
- return -EINVAL;
-
- if (dev->frame[b->index].state != F_UNUSED)
- return -EAGAIN;
-
- dev->frame[b->index].state = F_QUEUED;
-
- /* add frame to fifo */
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_add_tail(&dev->frame[b->index].frame, &dev->inqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- return 0;
+ return (videobuf_qbuf(&fh->vb_vidq, b));
}
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1230,46 +1447,24 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
int rc;
- struct em28xx_frame_t *f;
- unsigned long lock_flags;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&dev->outqueue)) {
- if (dev->stream == STREAM_OFF)
- return -EINVAL;
-
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- rc = wait_event_interruptible(dev->wait_frame,
- (!list_empty(&dev->outqueue)) ||
- (dev->state & DEV_DISCONNECTED));
- if (rc)
- return rc;
-
- if (dev->state & DEV_DISCONNECTED)
- return -ENODEV;
- }
-
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame);
- list_del(dev->outqueue.next);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- f->state = F_UNUSED;
- memcpy(b, &f->buf, sizeof(*b));
+ return (videobuf_dqbuf(&fh->vb_vidq, b,
+ file->f_flags & O_NONBLOCK));
+}
- if (f->vma_use_count)
- b->flags |= V4L2_BUF_FLAG_MAPPED;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct em28xx_fh *fh = priv;
- return 0;
+ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
}
+#endif
+
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
@@ -1375,17 +1570,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
{
int minor = iminor(inode);
int errCode = 0, radio = 0;
- struct em28xx *h,*dev = NULL;
+ struct em28xx *h, *dev = NULL;
struct em28xx_fh *fh;
+ enum v4l2_buf_type fh_type = 0;
list_for_each_entry(h, &em28xx_devlist, devlist) {
if (h->vdev->minor == minor) {
dev = h;
- dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
}
if (h->vbi_dev->minor == minor) {
dev = h;
- dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
}
if (h->radio_dev &&
h->radio_dev->minor == minor) {
@@ -1397,10 +1593,17 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
return -ENODEV;
em28xx_videodbg("open minor=%d type=%s users=%d\n",
- minor,v4l2_type_names[dev->type],dev->users);
+ minor, v4l2_type_names[fh_type], dev->users);
- fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
+#if 0
+ errCode = em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+ if (errCode < 0) {
+ em28xx_errdev("Device locked on digital mode. Can't open analog\n");
+ return -EBUSY;
+ }
+#endif
+ fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
if (!fh) {
em28xx_errdev("em28xx-video.c: Out of memory?!\n");
return -ENOMEM;
@@ -1408,32 +1611,28 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
mutex_lock(&dev->lock);
fh->dev = dev;
fh->radio = radio;
+ fh->type = fh_type;
filp->private_data = fh;
- if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
- dev->bytesperline = dev->width * 2;
dev->hscale = 0;
dev->vscale = 0;
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
em28xx_set_alternate(dev);
- em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev);
+ /* Needed, since GPIO might have disabled power of
+ some i2c device
+ */
+ em28xx_config_i2c(dev);
+
#if 0
/* device needs to be initialized before isoc transfer */
video_mux(dev, 0);
#endif
-
- /* start the transfer */
- errCode = em28xx_init_isoc(dev);
- if (errCode)
- goto err;
-
- em28xx_empty_framequeues(dev);
}
if (fh->radio) {
em28xx_videodbg("video_open: setting radio device\n");
@@ -1445,8 +1644,12 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->users++;
-err:
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
+ NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
+ sizeof(struct em28xx_buffer), fh);
+
mutex_unlock(&dev->lock);
+
return errCode;
}
@@ -1489,12 +1692,13 @@ static void em28xx_release_resources(struct em28xx *dev)
usb_put_dev(dev->udev);
/* Mark device as unused */
- em28xx_devused&=~(1<<dev->devno);
+ em28xx_devused &= ~(1<<dev->devno);
}
/*
* em28xx_v4l2_close()
- * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
*/
static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
{
@@ -1511,9 +1715,8 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
mutex_lock(&dev->lock);
if (dev->users == 1) {
- em28xx_uninit_isoc(dev);
- em28xx_release_buffers(dev);
- dev->io = IO_NONE;
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
/* the device is already disconnect,
free the remaining resources */
@@ -1524,6 +1727,10 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
return 0;
}
+ /* do this before setting alternate! */
+ em28xx_uninit_isoc(dev);
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+
/* set alternate 0 */
dev->alt = 0;
em28xx_videodbg("setting alternate 0\n");
@@ -1545,135 +1752,29 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
* will allocate buffers when called for the first time
*/
static ssize_t
-em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
- loff_t * f_pos)
+em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
{
- struct em28xx_frame_t *f, *i;
- unsigned long lock_flags;
- int ret = 0;
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
/* FIXME: read() is not prepared to allow changing the video
resolution while streaming. Seems a bug at em28xx_set_fmt
*/
- if (unlikely(res_get(fh) < 0))
- return -EBUSY;
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (unlikely(res_get(fh)))
+ return -EBUSY;
- mutex_lock(&dev->lock);
-
- if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
-
- if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
- em28xx_videodbg("not supported yet! ...\n");
- if (copy_to_user(buf, "", 1)) {
- mutex_unlock(&dev->lock);
- return -EFAULT;
- }
- mutex_unlock(&dev->lock);
- return (1);
+ return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
}
- if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
- em28xx_videodbg("not supported yet! ...\n");
- if (copy_to_user(buf, "", 1)) {
- mutex_unlock(&dev->lock);
- return -EFAULT;
- }
- mutex_unlock(&dev->lock);
- return (1);
- }
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("device not present\n");
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
-
- if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg("device misconfigured; close and open it again\n");
- mutex_unlock(&dev->lock);
- return -EIO;
- }
-
- if (dev->io == IO_MMAP) {
- em28xx_videodbg ("IO method is set to mmap; close and open"
- " the device again to choose the read method\n");
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- if (dev->io == IO_NONE) {
- if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
- em28xx_errdev("read failed, not enough memory\n");
- mutex_unlock(&dev->lock);
- return -ENOMEM;
- }
- dev->io = IO_READ;
- dev->stream = STREAM_ON;
- em28xx_queue_unusedframes(dev);
- }
-
- if (!count) {
- mutex_unlock(&dev->lock);
- return 0;
- }
-
- if (list_empty(&dev->outqueue)) {
- if (filp->f_flags & O_NONBLOCK) {
- mutex_unlock(&dev->lock);
- return -EAGAIN;
- }
- ret = wait_event_interruptible
- (dev->wait_frame,
- (!list_empty(&dev->outqueue)) ||
- (dev->state & DEV_DISCONNECTED));
- if (ret) {
- mutex_unlock(&dev->lock);
- return ret;
- }
- if (dev->state & DEV_DISCONNECTED) {
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
- dev->video_bytesread = 0;
- }
-
- f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
-
- em28xx_queue_unusedframes(dev);
-
- if (count > f->buf.length)
- count = f->buf.length;
-
- if ((dev->video_bytesread + count) > dev->frame_size)
- count = dev->frame_size - dev->video_bytesread;
-
- if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
- em28xx_err("Error while copying to user\n");
- return -EFAULT;
- }
- dev->video_bytesread += count;
-
- if (dev->video_bytesread == dev->frame_size) {
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_for_each_entry(i, &dev->outqueue, frame)
- i->state = F_UNUSED;
- INIT_LIST_HEAD(&dev->outqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- em28xx_queue_unusedframes(dev);
- dev->video_bytesread = 0;
- }
-
- *f_pos += count;
-
- mutex_unlock(&dev->lock);
-
- return count;
+ return 0;
}
/*
@@ -1682,46 +1783,21 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
*/
static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
{
- unsigned int mask = 0;
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
if (unlikely(res_get(fh) < 0))
return POLLERR;
- mutex_lock(&dev->lock);
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("device not present\n");
- } else if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg("device is misconfigured; close and open it again\n");
- } else {
- if (dev->io == IO_NONE) {
- if (!em28xx_request_buffers
- (dev, EM28XX_NUM_READ_FRAMES)) {
- em28xx_warn
- ("poll() failed, not enough memory\n");
- } else {
- dev->io = IO_READ;
- dev->stream = STREAM_ON;
- }
- }
-
- if (dev->io == IO_READ) {
- em28xx_queue_unusedframes(dev);
- poll_wait(filp, &dev->wait_frame, wait);
-
- if (!list_empty(&dev->outqueue))
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&dev->lock);
-
- return mask;
- }
- }
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
- mutex_unlock(&dev->lock);
- return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
}
/*
@@ -1731,69 +1807,23 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long start = vma->vm_start;
- void *pos;
- u32 i;
+ int rc;
if (unlikely(res_get(fh) < 0))
return -EBUSY;
- mutex_lock(&dev->lock);
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("mmap: device not present\n");
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
-
- if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg ("mmap: Device is misconfigured; close and "
- "open it again\n");
- mutex_unlock(&dev->lock);
- return -EIO;
- }
-
- if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) {
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- if (size > PAGE_ALIGN(dev->frame[0].buf.length))
- size = PAGE_ALIGN(dev->frame[0].buf.length);
-
- for (i = 0; i < dev->num_frames; i++) {
- if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
- if (i == dev->num_frames) {
- em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- /* VM_IO is eventually going to replace PageReserved altogether */
- vma->vm_flags |= VM_IO;
- vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
- pos = dev->frame[i].bufmem;
- while (size > 0) { /* size is page-aligned */
- if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- em28xx_videodbg("mmap: vm_insert_page failed\n");
- mutex_unlock(&dev->lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- vma->vm_ops = &em28xx_vm_ops;
- vma->vm_private_data = &dev->frame[i];
+ em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ rc);
- em28xx_vm_open(vma);
- mutex_unlock(&dev->lock);
- return 0;
+ return rc;
}
static const struct file_operations em28xx_v4l_fops = {
@@ -1827,22 +1857,22 @@ static const struct video_device em28xx_video_template = {
.minor = -1,
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
- .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
- .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
#if 0
- .vidioc_g_fmt_vbi = vidioc_g_fmt_vbi,
- .vidioc_try_fmt_vbi = vidioc_s_fmt_vbi,
- .vidioc_s_fmt_vbi = vidioc_s_fmt_vbi,
+ .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
#endif
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
- .vidioc_g_fmt_vbi_capture = vidioc_g_fmt_vbi_capture,
- .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture,
- .vidioc_s_fmt_vbi_capture = vidioc_try_set_vbi_capture,
+ .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
+ .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
+ .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
@@ -1865,6 +1895,9 @@ static const struct video_device em28xx_video_template = {
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
.tvnorms = V4L2_STD_ALL,
.current_norm = V4L2_STD_PAL,
@@ -1893,7 +1926,7 @@ static struct video_device em28xx_radio_template = {
#endif
};
-/******************************** usb interface *****************************************/
+/******************************** usb interface ******************************/
static LIST_HEAD(em28xx_extension_devlist);
@@ -1952,6 +1985,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
vfd->release = video_device_release;
#endif
vfd->type = type;
+ vfd->debug = video_debug;
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
dev->name, type_name);
@@ -1975,7 +2009,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->udev = udev;
mutex_init(&dev->lock);
- spin_lock_init(&dev->queue_lock);
+ spin_lock_init(&dev->slock);
init_waitqueue_head(&dev->open);
init_waitqueue_head(&dev->wait_frame);
init_waitqueue_head(&dev->wait_stream);
@@ -1987,10 +2021,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->em28xx_read_reg_req = em28xx_read_reg_req;
dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
- errCode = em28xx_read_reg(dev, CHIPID_REG);
- if (errCode >= 0)
- em28xx_info("em28xx chip ID = %d\n", errCode);
-
em28xx_pre_card_setup(dev);
errCode = em28xx_config(dev);
@@ -2023,10 +2053,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->width = maxw;
dev->height = maxh;
dev->interlaced = EM28XX_INTERLACED_DEFAULT;
- dev->field_size = dev->width * dev->height;
- dev->frame_size =
- dev->interlaced ? dev->field_size << 1 : dev->field_size;
- dev->bytesperline = dev->width * 2;
dev->hscale = 0;
dev->vscale = 0;
dev->ctl_input = 2;
@@ -2082,6 +2108,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->radio_dev->minor & 0x1f);
}
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vidq.queued);
+
#if 0
video_set_drvdata(dev->vbi_dev, dev);
#endif
@@ -2134,6 +2164,9 @@ static void request_module_async(struct work_struct *work)
request_module("snd-usb-audio");
else
request_module("em28xx-alsa");
+
+ if (dev->has_dvb)
+ request_module("em28xx-dvb");
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
@@ -2172,22 +2205,24 @@ static int em28xx_usb_probe(struct usb_interface *interface,
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
/* Check to see next free device and mark as used */
- nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS);
- em28xx_devused|=1<<nr;
+ nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+ em28xx_devused |= 1<<nr;
/* Don't register audio interfaces */
if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
- udev->descriptor.idVendor,udev->descriptor.idProduct,
+ udev->descriptor.idVendor,
+ udev->descriptor.idProduct,
ifnum,
interface->altsetting[0].desc.bInterfaceClass);
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
- udev->descriptor.idVendor,udev->descriptor.idProduct,
+ udev->descriptor.idVendor,
+ udev->descriptor.idProduct,
ifnum,
interface->altsetting[0].desc.bInterfaceClass);
@@ -2197,18 +2232,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
if (nr >= EM28XX_MAXBOARDS) {
- printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
- em28xx_devused&=~(1<<nr);
+ printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+ EM28XX_MAXBOARDS);
+ em28xx_devused &= ~(1<<nr);
return -ENOMEM;
}
@@ -2216,7 +2252,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
em28xx_err(DRIVER_NAME ": out of memory!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENOMEM;
}
@@ -2240,14 +2276,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* compute alternate max packet sizes */
uif = udev->actconfig->interface[0];
- dev->num_alt=uif->num_altsetting;
- em28xx_info("Alternate settings: %i\n",dev->num_alt);
-// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
- dev->alt_max_pkt_size = kmalloc(32*
- dev->num_alt,GFP_KERNEL);
+ dev->num_alt = uif->num_altsetting;
+ em28xx_info("Alternate settings: %i\n", dev->num_alt);
+/* dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */
+ dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
+
if (dev->alt_max_pkt_size == NULL) {
em28xx_errdev("out of memory!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
kfree(dev);
return -ENOMEM;
}
@@ -2257,11 +2293,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
wMaxPacketSize);
dev->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- em28xx_info("Alternate setting %i, max size= %i\n",i,
- dev->alt_max_pkt_size[i]);
+ em28xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->alt_max_pkt_size[i]);
}
- if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+ if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
dev->model = card[nr];
/* allocate device struct */
@@ -2297,7 +2333,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_info("disconnecting %s\n", dev->vdev->name);
- /* wait until all current v4l2 io is finished then deallocate resources */
+ /* wait until all current v4l2 io is finished then deallocate
+ resources */
mutex_lock(&dev->lock);
wake_up_interruptible_all(&dev->open);
@@ -2334,7 +2371,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
}
static struct usb_driver em28xx_usb_driver = {
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
.owner = THIS_MODULE,
#endif
.name = "em28xx",
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 980989f11..ed879653b 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -27,13 +27,43 @@
#include "compat.h"
#include <linux/videodev2.h>
+#include <media/videobuf-vmalloc.h>
+
#include <linux/i2c.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
#include <linux/mutex.h>
#endif
#include <media/ir-kbd-i2c.h>
-
-#define UNSET -1
+#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
+#include <media/videobuf-dvb.h>
+#endif
+#include "tuner-xc2028.h"
+#include "em28xx-reg.h"
+
+/* Boards supported by driver */
+#define EM2800_BOARD_UNKNOWN 0
+#define EM2820_BOARD_UNKNOWN 1
+#define EM2820_BOARD_TERRATEC_CINERGY_250 2
+#define EM2820_BOARD_PINNACLE_USB_2 3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
+#define EM2820_BOARD_MSI_VOX_USB_2 5
+#define EM2800_BOARD_TERRATEC_CINERGY_200 6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
+#define EM2800_BOARD_KWORLD_USB2800 8
+#define EM2820_BOARD_PINNACLE_DVC_90 9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
+#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
+#define EM2800_BOARD_VGEAR_POCKETTV 15
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16
+#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18
+
+/* Limits minimum and default number of buffers */
+#define EM28XX_MIN_BUF 4
+#define EM28XX_DEF_BUF 8
/* maximum number of em28xx boards */
#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
@@ -84,31 +114,78 @@
/* time in msecs to wait for i2c writes to finish */
#define EM2800_I2C_WRITE_TIMEOUT 20
-/* the various frame states */
-enum em28xx_frame_state {
- F_UNUSED = 0,
- F_QUEUED,
- F_GRABBING,
- F_DONE,
- F_ERROR,
+enum em28xx_mode {
+ EM28XX_MODE_UNDEFINED,
+ EM28XX_ANALOG_MODE,
+ EM28XX_DIGITAL_MODE,
};
-/* stream states */
enum em28xx_stream_state {
STREAM_OFF,
STREAM_INTERRUPT,
STREAM_ON,
};
-/* frames */
-struct em28xx_frame_t {
- void *bufmem;
- struct v4l2_buffer buf;
- enum em28xx_frame_state state;
+struct em28xx;
+
+struct em28xx_usb_isoc_ctl {
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for isoc transfers */
+ struct urb **urb;
+
+ /* transfer buffers for isoc transfer */
+ char **transfer_buffer;
+
+ /* Last buffer command and region */
+ u8 cmd;
+ int pos, size, pktsize;
+
+ /* Last field: ODD or EVEN? */
+ int field;
+
+ /* Stores incomplete commands */
+ u32 tmp_buf;
+ int tmp_buf_len;
+
+ /* Stores already requested buffers */
+ struct em28xx_buffer *buf;
+
+ /* Stores the number of received fields */
+ int nfields;
+
+ /* isoc urb callback */
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
+
+};
+
+struct em28xx_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+};
+
+/* buffer for one video frame */
+struct em28xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
struct list_head frame;
- unsigned long vma_use_count;
int top_field;
- int fieldbytesused;
+ int receiving;
+};
+
+struct em28xx_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+
+ wait_queue_head_t wq;
+
+ /* Counters to control buffer fill */
+ int pos;
};
/* io methods */
@@ -155,6 +232,12 @@ enum em28xx_decoder {
EM28XX_SAA7114
};
+struct em28xx_reg_seq {
+ int reg;
+ unsigned char val, mask;
+ int sleep;
+};
+
struct em28xx_board {
char *name;
int vchannels;
@@ -168,8 +251,7 @@ struct em28xx_board {
unsigned int mts_firmware:1;
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
-
- unsigned int analog_gpio;
+ unsigned int has_dvb:1;
enum em28xx_decoder decoder;
@@ -202,7 +284,10 @@ enum em28xx_dev_state {
#define EM28XX_NUM_AUDIO_PACKETS 64
#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
#define EM28XX_CAPTURE_STREAM_EN 1
+
+/* em28xx extensions */
#define EM28XX_AUDIO 0x10
+#define EM28XX_DVB 0x20
struct em28xx_audio {
char name[50];
@@ -228,13 +313,24 @@ struct em28xx_audio {
spinlock_t slock;
};
+struct em28xx;
+
+struct em28xx_fh {
+ struct em28xx *dev;
+ unsigned int stream_on:1; /* Locks streams */
+ int radio;
+
+ struct videobuf_queue vb_vidq;
+
+ enum v4l2_buf_type type;
+};
+
/* main device struct */
struct em28xx {
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
- unsigned int analog_gpio;
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
unsigned int has_tda9887:1;
@@ -242,6 +338,16 @@ struct em28xx {
unsigned int has_audio_class:1;
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
+ unsigned int has_dvb:1;
+
+ /* Some older em28xx chips needs a waiting time after writing */
+ unsigned int wait_after_write;
+
+ /* GPIO sequences for analog and digital mode */
+ struct em28xx_reg_seq *analog_gpio, *digital_gpio;
+
+ /* GPIO sequences for tuner callbacks */
+ struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio;
int video_inputs; /* number of video inputs */
struct list_head devlist;
@@ -266,40 +372,32 @@ struct em28xx {
int mute;
int volume;
/* frame properties */
- struct em28xx_frame_t frame[EM28XX_NUM_FRAMES]; /* list of frames */
- int num_frames; /* number of frames currently in use */
- unsigned int frame_count; /* total number of transfered frames */
- struct em28xx_frame_t *frame_current; /* the frame that is being filled */
int width; /* current frame width */
int height; /* current frame height */
- int frame_size; /* current frame size */
- int field_size; /* current field size */
- int bytesperline;
int hscale; /* horizontal scale factor (see datasheet) */
int vscale; /* vertical scale factor (see datasheet) */
int interlaced; /* 1=interlace fileds, 0=just top fileds */
- int type;
unsigned int video_bytesread; /* Number of bytes read */
unsigned long hash; /* eeprom hash - for boards with generic ID */
- unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */
+ unsigned long i2c_hash; /* i2c devicelist hash -
+ for boards with generic ID */
struct em28xx_audio *adev;
/* states */
enum em28xx_dev_state state;
- enum em28xx_stream_state stream;
enum em28xx_io_method io;
struct work_struct request_module_wk;
/* locks */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
struct mutex lock;
#else
struct semaphore lock, fileop_lock;
#endif
- spinlock_t queue_lock;
+ /* spinlock_t queue_lock; */
struct list_head inqueue, outqueue;
wait_queue_head_t open, wait_frame, wait_stream;
struct video_device *vbi_dev;
@@ -307,6 +405,11 @@ struct em28xx {
unsigned char eedata[256];
+ /* Isoc control struct */
+ struct em28xx_dmaqueue vidq;
+ struct em28xx_usb_isoc_ctl isoc_ctl;
+ spinlock_t slock;
+
/* usb transfer */
struct usb_device *udev; /* the usb device */
int alt; /* alternate */
@@ -316,20 +419,21 @@ struct em28xx {
struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */
char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
/* helper funcs that call usb_control_msg */
- int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf,
- int len);
- int (*em28xx_read_reg) (struct em28xx * dev, u16 reg);
- int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg,
+ int (*em28xx_write_regs) (struct em28xx *dev, u16 reg,
char *buf, int len);
- int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg,
+ int (*em28xx_read_reg) (struct em28xx *dev, u16 reg);
+ int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg,
char *buf, int len);
- int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
-};
+ int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg);
-struct em28xx_fh {
- struct em28xx *dev;
- unsigned int stream_on:1; /* Locks streams */
- int radio;
+ enum em28xx_mode mode;
+
+ /* Caches GPO and GPIO registers */
+ unsigned char reg_gpo, reg_gpio;
+
+ struct em28xx_dvb *dvb;
};
struct em28xx_ops {
@@ -366,22 +470,27 @@ int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
int em28xx_outfmt_set_yuv422(struct em28xx *dev);
int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_init_isoc(struct em28xx *dev);
-void em28xx_uninit_isoc(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
+int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
+void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
/* Provided by em28xx-video.c */
int em28xx_register_extension(struct em28xx_ops *dev);
void em28xx_unregister_extension(struct em28xx_ops *dev);
/* Provided by em28xx-cards.c */
-extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern int em2800_variant_detect(struct usb_device *udev, int model);
extern void em28xx_pre_card_setup(struct em28xx *dev);
extern void em28xx_card_setup(struct em28xx *dev);
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
extern const unsigned int em28xx_bcount;
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+int em28xx_tuner_callback(void *ptr, int command, int arg);
/* Provided by em28xx-input.c */
/* TODO: Check if the standard get_key handlers on ir-common can be used */
@@ -390,71 +499,6 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw);
-/* em2800 registers */
-#define EM2800_AUDIOSRC_REG 0x08
-
-/* em28xx registers */
-#define I2C_CLK_REG 0x06
-#define CHIPID_REG 0x0a
-#define USBSUSP_REG 0x0c /* */
-
-#define AUDIOSRC_REG 0x0e
-#define XCLK_REG 0x0f
-
-#define VINMODE_REG 0x10
-#define VINCTRL_REG 0x11
-#define VINENABLE_REG 0x12 /* */
-
-#define GAMMA_REG 0x14
-#define RGAIN_REG 0x15
-#define GGAIN_REG 0x16
-#define BGAIN_REG 0x17
-#define ROFFSET_REG 0x18
-#define GOFFSET_REG 0x19
-#define BOFFSET_REG 0x1a
-
-#define OFLOW_REG 0x1b
-#define HSTART_REG 0x1c
-#define VSTART_REG 0x1d
-#define CWIDTH_REG 0x1e
-#define CHEIGHT_REG 0x1f
-
-#define YGAIN_REG 0x20
-#define YOFFSET_REG 0x21
-#define UVGAIN_REG 0x22
-#define UOFFSET_REG 0x23
-#define VOFFSET_REG 0x24
-#define SHARPNESS_REG 0x25
-
-#define COMPR_REG 0x26
-#define OUTFMT_REG 0x27
-
-#define XMIN_REG 0x28
-#define XMAX_REG 0x29
-#define YMIN_REG 0x2a
-#define YMAX_REG 0x2b
-
-#define HSCALELOW_REG 0x30
-#define HSCALEHIGH_REG 0x31
-#define VSCALELOW_REG 0x32
-#define VSCALEHIGH_REG 0x33
-
-#define AC97LSB_REG 0x40
-#define AC97MSB_REG 0x41
-#define AC97ADDR_REG 0x42
-#define AC97BUSY_REG 0x43
-
-/* em202 registers */
-#define MASTER_AC97 0x02
-#define LINE_IN_AC97 0x10
-#define VIDEO_AC97 0x14
-
-/* register settings */
-#define EM2800_AUDIO_SRC_TUNER 0x0d
-#define EM2800_AUDIO_SRC_LINE 0x0c
-#define EM28XX_AUDIO_SRC_TUNER 0xc0
-#define EM28XX_AUDIO_SRC_LINE 0x80
-
/* printk macros */
#define em28xx_err(fmt, arg...) do {\
@@ -471,80 +515,80 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
printk(KERN_WARNING "%s: "fmt,\
dev->name , ##arg); } while (0)
-inline static int em28xx_compression_disable(struct em28xx *dev)
+static inline int em28xx_compression_disable(struct em28xx *dev)
{
/* side effect of disabling scaler and mixer */
- return em28xx_write_regs(dev, COMPR_REG, "\x00", 1);
+ return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1);
}
-inline static int em28xx_contrast_get(struct em28xx *dev)
+static inline int em28xx_contrast_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, YGAIN_REG) & 0x1f;
+ return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f;
}
-inline static int em28xx_brightness_get(struct em28xx *dev)
+static inline int em28xx_brightness_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, YOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R21_YOFFSET);
}
-inline static int em28xx_saturation_get(struct em28xx *dev)
+static inline int em28xx_saturation_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f;
+ return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f;
}
-inline static int em28xx_u_balance_get(struct em28xx *dev)
+static inline int em28xx_u_balance_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, UOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R23_UOFFSET);
}
-inline static int em28xx_v_balance_get(struct em28xx *dev)
+static inline int em28xx_v_balance_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, VOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R24_VOFFSET);
}
-inline static int em28xx_gamma_get(struct em28xx *dev)
+static inline int em28xx_gamma_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, GAMMA_REG) & 0x3f;
+ return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f;
}
-inline static int em28xx_contrast_set(struct em28xx *dev, s32 val)
+static inline int em28xx_contrast_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1);
}
-inline static int em28xx_brightness_set(struct em28xx *dev, s32 val)
+static inline int em28xx_brightness_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1);
}
-inline static int em28xx_saturation_set(struct em28xx *dev, s32 val)
+static inline int em28xx_saturation_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1);
}
-inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1);
}
-inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1);
}
-inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1);
}
/*FIXME: maxw should be dependent of alt mode */
-inline static unsigned int norm_maxw(struct em28xx *dev)
+static inline unsigned int norm_maxw(struct em28xx *dev)
{
if (dev->max_range_640_480)
return 640;
@@ -552,7 +596,7 @@ inline static unsigned int norm_maxw(struct em28xx *dev)
return 720;
}
-inline static unsigned int norm_maxh(struct em28xx *dev)
+static inline unsigned int norm_maxh(struct em28xx *dev)
{
if (dev->max_range_640_480)
return 480;
diff --git a/linux/drivers/media/video/et61x251/et61x251.h b/linux/drivers/media/video/et61x251/et61x251.h
index d22fbd34a..64ff5de0d 100644
--- a/linux/drivers/media/video/et61x251/et61x251.h
+++ b/linux/drivers/media/video/et61x251/et61x251.h
@@ -206,7 +206,7 @@ do { \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
- __FILE__, __FUNCTION__, __LINE__ , ## args); \
+ __FILE__, __func__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -216,7 +216,7 @@ do { \
pr_info("et61x251: " fmt "\n", ## args); \
else if ((level) == 3) \
pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -232,7 +232,7 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
__LINE__ , ## args)
#undef PDBGG
diff --git a/linux/drivers/media/video/et61x251/et61x251_core.c b/linux/drivers/media/video/et61x251/et61x251_core.c
index 27e1da696..4d08f0225 100644
--- a/linux/drivers/media/video/et61x251/et61x251_core.c
+++ b/linux/drivers/media/video/et61x251/et61x251_core.c
@@ -34,7 +34,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c
index 198e0a18b..9a8795523 100644
--- a/linux/drivers/media/video/ir-kbd-i2c.c
+++ b/linux/drivers/media/video/ir-kbd-i2c.c
@@ -40,7 +40,6 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/workqueue.h>
-#include <asm/semaphore.h>
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
@@ -155,7 +154,7 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
}
if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0)
- dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__,
+ dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__,
buf[0], buf[1], buf[2], buf[3]);
/* no key pressed or signal from other ir remote */
@@ -531,8 +530,11 @@ static int ir_probe(struct i2c_adapter *adap)
static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
static const int probe_cx23885[] = { 0x6b, -1 };
const int *probe;
- struct i2c_client *c;
- unsigned char buf;
+ struct i2c_msg msg = {
+ .flags = I2C_M_RD,
+ .len = 0,
+ .buf = NULL,
+ };
int i, rc;
switch (adap->id) {
@@ -558,23 +560,17 @@ static int ir_probe(struct i2c_adapter *adap)
return 0;
}
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c)
- return -ENOMEM;
-
- c->adapter = adap;
for (i = 0; -1 != probe[i]; i++) {
- c->addr = probe[i];
- rc = i2c_master_recv(c, &buf, 0);
+ msg.addr = probe[i];
+ rc = i2c_transfer(adap, &msg, 1);
dprintk(1,"probe 0x%02x @ %s: %s\n",
probe[i], adap->name,
- (0 == rc) ? "yes" : "no");
- if (0 == rc) {
+ (1 == rc) ? "yes" : "no");
+ if (1 == rc) {
ir_attach(adap, probe[i], 0, 0);
break;
}
}
- kfree(c);
return 0;
}
diff --git a/linux/drivers/media/video/ivtv/Kconfig b/linux/drivers/media/video/ivtv/Kconfig
index 270906fc3..5d7ee8fcd 100644
--- a/linux/drivers/media/video/ivtv/Kconfig
+++ b/linux/drivers/media/video/ivtv/Kconfig
@@ -1,6 +1,8 @@
config VIDEO_IVTV
tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+ depends on INPUT # due to VIDEO_IR
+ depends on HOTPLUG # due to FW_LOADER
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_IR
@@ -10,6 +12,7 @@ config VIDEO_IVTV
select VIDEO_CX25840
select VIDEO_MSP3400
select VIDEO_SAA711X
+ select VIDEO_SAA717X
select VIDEO_SAA7127
select VIDEO_TVAUDIO
select VIDEO_CS53L32A
diff --git a/linux/drivers/media/video/ivtv/Makefile b/linux/drivers/media/video/ivtv/Makefile
index a0389014f..26ce0d6ea 100644
--- a/linux/drivers/media/video/ivtv/Makefile
+++ b/linux/drivers/media/video/ivtv/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/video/ivtv/ivtv-cards.c b/linux/drivers/media/video/ivtv/ivtv-cards.c
index 92e4b85f9..03455fb30 100644
--- a/linux/drivers/media/video/ivtv/ivtv-cards.c
+++ b/linux/drivers/media/video/ivtv/ivtv-cards.c
@@ -40,6 +40,8 @@
#define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM)
+
/* usual i2c tuner addresses to probe */
static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
.radio = { I2C_CLIENT_END },
@@ -298,7 +300,7 @@ static const struct ivtv_card ivtv_card_mpg600 = {
.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
.tuners = {
/* The PAL tuner is confirmed */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_mpg600,
@@ -339,7 +341,7 @@ static const struct ivtv_card ivtv_card_mpg160 = {
.lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 },
.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_mpg160,
@@ -375,7 +377,7 @@ static const struct ivtv_card ivtv_card_pg600 = {
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
},
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_pg600,
@@ -416,7 +418,7 @@ static const struct ivtv_card ivtv_card_avc2410 = {
on the country/region setting of the user to decide which tuner
is available. */
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP,
.tuner = TUNER_PHILIPS_FM1236_MK3 },
{ .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 },
@@ -490,7 +492,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = {
.gpio_video_input = { .mask = 0x0030, .tuner = 0x0000,
.composite = 0x0010, .svideo = 0x0020 },
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_tg5000tv,
.i2c = &ivtv_i2c_std,
@@ -521,7 +523,7 @@ static const struct ivtv_card ivtv_card_va2000 = {
{ IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER },
},
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_va2000,
.i2c = &ivtv_i2c_std,
@@ -565,7 +567,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.pci_list = ivtv_pci_cx23416gyc,
@@ -597,7 +599,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.i2c = &ivtv_i2c_std,
@@ -627,7 +629,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.i2c = &ivtv_i2c_std,
@@ -667,7 +669,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
.gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 },
.tuners = {
/* This card has the Panasonic VP27 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
},
.pci_list = ivtv_pci_gv_mvprx,
.i2c = &ivtv_i2c_std,
@@ -704,7 +706,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
.gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 },
.tuners = {
/* This card has the Panasonic VP27 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
},
.pci_list = ivtv_pci_gv_mvprx2e,
.i2c = &ivtv_i2c_std,
@@ -739,7 +741,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
.gpio_init = { .direction = 0xf000, .initial_value = 0xA000 },
.tuners = {
/* This card has a Philips FQ1216ME MK3 tuner */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
},
.pci_list = ivtv_pci_gotview_pci_dvd,
.i2c = &ivtv_i2c_std,
@@ -778,7 +780,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
.gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
.tuners = {
/* This card has a Philips FQ1216ME MK5 tuner */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
},
.pci_list = ivtv_pci_gotview_pci_dvd2,
.i2c = &ivtv_i2c_std,
@@ -856,7 +858,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
.gpio_video_input = { .mask = 0x0030, .tuner = 0x0000,
.composite = 0x0010, .svideo = 0x0020},
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_dctmvtvp1,
.i2c = &ivtv_i2c_std,
@@ -875,6 +877,7 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
static const struct ivtv_card ivtv_card_pg600v2 = {
.type = IVTV_CARD_PG600V2,
.name = "Yuan PG600-2, GotView PCI DVD Lite",
+ .comment = "only Composite and S-Video inputs are supported, not the tuner\n",
.v4l2_capabilities = IVTV_CAP_ENCODER,
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
@@ -894,7 +897,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
- .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
+ .xceive_pin = 12,
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
@@ -941,7 +944,7 @@ static const struct ivtv_card ivtv_card_club3d = {
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
- .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
+ .xceive_pin = 12,
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
@@ -965,34 +968,22 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
.hw_audio_ctrl = IVTV_HW_CX25840,
-#if 0
- /* XC2028 support has problems with fw loading on this card,
- so don't support this tuner for this card until this issue
- has been solved. */
.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
.video_inputs = {
- { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 },
- { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+ { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
},
.audio_inputs = {
+ { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
},
/* enable line-in */
- .gpio_init = { .direction = 0xf000, .initial_value = 0x5000 },
+ .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 },
+ .xceive_pin = 10,
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
-#else
- .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
- .video_inputs = {
- { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 },
- { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
- },
- .audio_inputs = {
- { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
- },
- .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
-#endif
.pci_list = ivtv_pci_avertv_mce116,
.i2c = &ivtv_i2c_std,
};
@@ -1030,7 +1021,7 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = {
.gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
.tuners = {
/* This card has a Partsnic PTI-5NF05 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
},
.pci_list = ivtv_pci_aver_pvr150,
.i2c = &ivtv_i2c_radio,
@@ -1098,12 +1089,83 @@ static const struct ivtv_card ivtv_card_asus_falcon2 = {
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.pci_list = ivtv_pci_asus_falcon2,
.i2c = &ivtv_i2c_std,
};
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia M104 miniPCI card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_m104 = {
+ .type = IVTV_CARD_AVER_M104,
+ .name = "AVerMedia M104",
+ .comment = "Not yet supported!\n",
+ .v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/
+ .hw_video = IVTV_HW_CX25840,
+ .hw_audio = IVTV_HW_CX25840,
+ .hw_audio_ctrl = IVTV_HW_CX25840,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
+ },
+ .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+ /* enable line-in + reset tuner */
+ .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 },
+ .xceive_pin = 10,
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .pci_list = ivtv_pci_aver_m104,
+ .i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Buffalo PC-MV5L/PCI cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_buffalo[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x052b },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_buffalo = {
+ .type = IVTV_CARD_BUFFALO_MV5L,
+ .name = "Buffalo PC-MV5L/PCI",
+ .v4l2_capabilities = IVTV_CAP_ENCODER,
+ .hw_video = IVTV_HW_CX25840,
+ .hw_audio = IVTV_HW_CX25840,
+ .hw_audio_ctrl = IVTV_HW_CX25840,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1,
+ CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
+ },
+ .xceive_pin = 12,
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .pci_list = ivtv_pci_buffalo,
+ .i2c = &ivtv_i2c_std,
+};
+
static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_pvr250,
&ivtv_card_pvr350,
@@ -1129,6 +1191,8 @@ static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_asus_falcon2,
&ivtv_card_aver_pvr150,
&ivtv_card_aver_ezmaker,
+ &ivtv_card_aver_m104,
+ &ivtv_card_buffalo,
/* Variations of standard cards but with the same PCI IDs.
These cards must come last in this list. */
@@ -1160,7 +1224,8 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input)
if (index >= itv->nof_inputs)
return -EINVAL;
input->index = index;
- strcpy(input->name, input_strs[card_input->video_type - 1]);
+ strlcpy(input->name, input_strs[card_input->video_type - 1],
+ sizeof(input->name));
input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ?
V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
input->audioset = (1 << itv->nof_audio_inputs) - 1;
@@ -1177,7 +1242,7 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output)
if (index >= itv->card->nof_outputs)
return -EINVAL;
output->index = index;
- strcpy(output->name, card_output->name);
+ strlcpy(output->name, card_output->name, sizeof(output->name));
output->type = V4L2_OUTPUT_TYPE_ANALOG;
output->audioset = 1;
output->std = V4L2_STD_ALL;
@@ -1196,7 +1261,8 @@ int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio)
memset(audio, 0, sizeof(*audio));
if (index >= itv->nof_audio_inputs)
return -EINVAL;
- strcpy(audio->name, input_strs[aud_input->audio_type - 1]);
+ strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
+ sizeof(audio->name));
audio->index = index;
audio->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -1207,6 +1273,6 @@ int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud
memset(aud_output, 0, sizeof(*aud_output));
if (itv->card->video_outputs == NULL || index != 0)
return -EINVAL;
- strcpy(aud_output->name, "A/V Audio Out");
+ strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name));
return 0;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-cards.h b/linux/drivers/media/video/ivtv/ivtv-cards.h
index 9186fa2ee..381af1bce 100644
--- a/linux/drivers/media/video/ivtv/ivtv-cards.h
+++ b/linux/drivers/media/video/ivtv/ivtv-cards.h
@@ -48,7 +48,9 @@
#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */
#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */
#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */
-#define IVTV_CARD_LAST 23
+#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */
+#define IVTV_CARD_BUFFALO_MV5L 25 /* Buffalo PC-MV5L/PCI card */
+#define IVTV_CARD_LAST 25
/* Variants of existing cards but with the same PCI IDs. The driver
detects these based on other device information.
@@ -244,6 +246,7 @@ struct ivtv_card_tuner_i2c {
struct ivtv_card {
int type;
char *name;
+ char *comment;
u32 v4l2_capabilities;
u32 hw_video; /* hardware used to process video */
u32 hw_audio; /* hardware used to process audio */
@@ -256,6 +259,7 @@ struct ivtv_card {
int nof_outputs;
const struct ivtv_card_output *video_outputs;
u8 gr_config; /* config byte for the ghost reduction device */
+ u8 xceive_pin; /* XCeive tuner GPIO reset pin */
/* GPIO card-specific settings */
struct ivtv_gpio_init gpio_init;
diff --git a/linux/drivers/media/video/ivtv/ivtv-controls.c b/linux/drivers/media/video/ivtv/ivtv-controls.c
index 8c02fa661..c7e449f63 100644
--- a/linux/drivers/media/video/ivtv/ivtv-controls.c
+++ b/linux/drivers/media/video/ivtv/ivtv-controls.c
@@ -181,12 +181,12 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm
return 0;
}
/* Need sliced data for mpeg insertion */
- if (get_service_set(itv->vbi.sliced_in) == 0) {
+ if (ivtv_get_service_set(itv->vbi.sliced_in) == 0) {
if (itv->is_60hz)
itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
else
itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
- expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
+ ivtv_expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
}
return 0;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c
index b8b0ac859..094f5524f 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.c
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.c
@@ -190,6 +190,8 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t22 = ASUS Falcon2\n"
"\t\t\t23 = AverMedia PVR-150 Plus\n"
"\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
+ "\t\t\t25 = AverMedia M104 (not yet working)\n"
+ "\t\t\t26 = Buffalo PC-MV5L/PCI\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
@@ -856,6 +858,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
return 0;
}
+#ifdef MODULE
static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
const char *name, u32 id)
{
@@ -868,14 +871,16 @@ static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
IVTV_DEBUG_INFO("Loaded module %s\n", name);
return hw;
}
+#endif
static void ivtv_load_and_init_modules(struct ivtv *itv)
{
u32 hw = itv->card->hw_all;
unsigned i;
+#ifdef MODULE
/* load modules */
-#ifndef CONFIG_VIDEO_TUNER
+#ifndef CONFIG_MEDIA_TUNER
hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
#endif
#ifndef CONFIG_VIDEO_CX25840
@@ -887,7 +892,9 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
#ifndef CONFIG_VIDEO_SAA7127
hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
#endif
+#ifndef CONFIG_VIDEO_SAA717X
hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
+#endif
#ifndef CONFIG_VIDEO_UPD64031A
hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
#endif
@@ -912,6 +919,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
#ifndef CONFIG_VIDEO_M52790
hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
#endif
+#endif
/* check which i2c devices are actually found */
for (i = 0; i < 32; i++) {
@@ -1016,7 +1024,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
ivtv_cards[ivtv_cards_active] = itv;
itv->dev = dev;
itv->num = ivtv_cards_active++;
- snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
+ snprintf(itv->name, sizeof(itv->name), "ivtv%d", itv->num);
IVTV_INFO("Initializing card #%d\n", itv->num);
spin_unlock(&ivtv_cards_lock);
@@ -1050,7 +1058,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_ENCODER_SIZE);
if (!itv->enc_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1062,7 +1070,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_DECODER_SIZE);
if (!itv->dec_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1078,7 +1086,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (!itv->reg_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_io;
}
@@ -1099,6 +1107,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
The PCI IDs are not always reliable. */
ivtv_process_eeprom(itv);
}
+ if (itv->card->comment)
+ IVTV_INFO("%s", itv->card->comment);
+ if (itv->card->v4l2_capabilities == 0) {
+ /* card was detected but is not supported */
+ retval = -ENODEV;
+ goto free_i2c;
+ }
if (itv->std == 0) {
itv->std = V4L2_STD_NTSC_M;
@@ -1197,13 +1212,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
}
- retval = ivtv_streams_setup(itv);
- if (retval) {
- IVTV_ERR("Error %d setting up streams\n", retval);
- goto free_i2c;
- }
-
- IVTV_DEBUG_IRQ("Masking interrupts\n");
/* clear interrupt mask, effectively disabling interrupts */
ivtv_set_irq_mask(itv, 0xffffffff);
@@ -1212,32 +1220,38 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv);
if (retval) {
IVTV_ERR("Failed to register irq %d\n", retval);
- goto free_streams;
+ goto free_i2c;
+ }
+
+ retval = ivtv_streams_setup(itv);
+ if (retval) {
+ IVTV_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
}
retval = ivtv_streams_register(itv);
if (retval) {
IVTV_ERR("Error %d registering devices\n", retval);
- goto free_irq;
+ goto free_streams;
}
IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
return 0;
- free_irq:
+free_streams:
+ ivtv_streams_cleanup(itv, 1);
+free_irq:
free_irq(itv->dev->irq, (void *)itv);
- free_streams:
- ivtv_streams_cleanup(itv);
- free_i2c:
+free_i2c:
exit_ivtv_i2c(itv);
- free_io:
+free_io:
ivtv_iounmap(itv);
- free_mem:
+free_mem:
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
- free_workqueue:
+free_workqueue:
destroy_workqueue(itv->irq_work_queues);
- err:
+err:
if (retval == 0)
retval = -ENODEV;
IVTV_ERR("Error %d on initialization\n", retval);
@@ -1368,7 +1382,7 @@ static void ivtv_remove(struct pci_dev *pci_dev)
flush_workqueue(itv->irq_work_queues);
destroy_workqueue(itv->irq_work_queues);
- ivtv_streams_cleanup(itv);
+ ivtv_streams_cleanup(itv, 1);
ivtv_udma_free(itv);
exit_ivtv_i2c(itv);
diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h
index ba8763f62..5134d8a09 100644
--- a/linux/drivers/media/video/ivtv/ivtv-driver.h
+++ b/linux/drivers/media/video/ivtv/ivtv-driver.h
@@ -262,6 +262,12 @@ struct ivtv_mailbox_data {
/* Scatter-Gather array element, used in DMA transfers */
struct ivtv_sg_element {
+ __le32 src;
+ __le32 dst;
+ __le32 size;
+};
+
+struct ivtv_sg_host_element {
u32 src;
u32 dst;
u32 size;
@@ -356,8 +362,8 @@ struct ivtv_stream {
u16 dma_xfer_cnt;
/* Base Dev SG Array for cx23415/6 */
- struct ivtv_sg_element *sg_pending;
- struct ivtv_sg_element *sg_processing;
+ struct ivtv_sg_host_element *sg_pending;
+ struct ivtv_sg_host_element *sg_processing;
struct ivtv_sg_element *sg_dma;
dma_addr_t sg_handle;
int sg_pending_size;
diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c
index d949a8133..db813e071 100644
--- a/linux/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c
@@ -219,7 +219,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
/* Process pending program info updates and pending VBI data */
ivtv_update_pgm_info(itv);
- if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
+ if (time_after(jiffies,
+ itv->dualwatch_jiffies +
+ msecs_to_jiffies(1000))) {
itv->dualwatch_jiffies = jiffies;
ivtv_dualwatch(itv);
}
@@ -585,7 +587,7 @@ retry:
since we may get here before the stream has been fully set-up */
if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
while (count >= itv->dma_data_req_size) {
- if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
+ if (!ivtv_yuv_udma_stream_frame (itv, (void __user *)user_buf)) {
bytes_written += itv->dma_data_req_size;
user_buf += itv->dma_data_req_size;
count -= itv->dma_data_req_size;
@@ -753,8 +755,10 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
IVTV_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
- if (eof || s->q_full.length || s->q_io.length)
+ if (s->q_full.length || s->q_io.length)
return POLLIN | POLLRDNORM;
+ if (eof)
+ return POLLHUP;
return 0;
}
@@ -983,6 +987,8 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
/* Find which card this open was on */
spin_lock(&ivtv_cards_lock);
for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
+ if (ivtv_cards[x] == NULL)
+ continue;
/* find out which stream this open was on */
for (y = 0; y < IVTV_MAX_STREAMS; y++) {
s = &ivtv_cards[x]->streams[y];
diff --git a/linux/drivers/media/video/ivtv/ivtv-gpio.c b/linux/drivers/media/video/ivtv/ivtv-gpio.c
index 688cd3856..bc22905ea 100644
--- a/linux/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/linux/drivers/media/video/ivtv/ivtv-gpio.c
@@ -128,20 +128,17 @@ int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
{
struct i2c_algo_bit_data *algo = dev;
struct ivtv *itv = algo->data;
- int curdir, curout;
+ u32 curout;
if (cmd != XC2028_TUNER_RESET)
return 0;
IVTV_DEBUG_INFO("Resetting tuner\n");
curout = read_reg(IVTV_REG_GPIO_OUT);
- curdir = read_reg(IVTV_REG_GPIO_DIR);
- curdir |= (1 << 12); /* GPIO bit 12 */
-
- curout &= ~(1 << 12);
+ curout &= ~(1 << itv->card->xceive_pin);
write_reg(curout, IVTV_REG_GPIO_OUT);
schedule_timeout_interruptible(msecs_to_jiffies(1));
- curout |= (1 << 12);
+ curout |= 1 << itv->card->xceive_pin;
write_reg(curout, IVTV_REG_GPIO_OUT);
schedule_timeout_interruptible(msecs_to_jiffies(1));
return 0;
@@ -149,15 +146,20 @@ int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
void ivtv_gpio_init(struct ivtv *itv)
{
- if (itv->card->gpio_init.direction == 0)
+ u16 pin = 0;
+
+ if (itv->card->xceive_pin)
+ pin = 1 << itv->card->xceive_pin;
+
+ if ((itv->card->gpio_init.direction | pin) == 0)
return;
IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
/* init output data then direction */
- write_reg(itv->card->gpio_init.initial_value, IVTV_REG_GPIO_OUT);
- write_reg(itv->card->gpio_init.direction, IVTV_REG_GPIO_DIR);
+ write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
+ write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
}
static struct v4l2_queryctrl gpio_ctrl_mute = {
diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c
index 1f421a574..b9e38c849 100644
--- a/linux/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c
@@ -136,7 +136,7 @@ static const u8 hw_addrs[] = {
};
/* This array should match the IVTV_HW_ defines */
-static const char * const hw_drivernames[] = {
+static const char * const hw_devicenames[] = {
"cx25840",
"saa7115",
"saa7127",
@@ -145,7 +145,7 @@ static const char * const hw_drivernames[] = {
"wm8775",
"cs53l32a",
"tveeprom",
- "saa7115",
+ "saa7114",
"upd64031a",
"upd64083",
"saa717x",
@@ -168,7 +168,12 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
return -1;
id = hw_driverids[idx];
memset(&info, 0, sizeof(info));
- strcpy(info.driver_name, hw_drivernames[idx]);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ strlcpy(info.driver_name, hw_devicenames[idx],
+ sizeof(info.driver_name));
+#else
+ strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
+#endif
info.addr = hw_addrs[idx];
for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
@@ -178,10 +183,16 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
}
if (id != I2C_DRIVERID_TUNER) {
- c = i2c_new_device(&itv->i2c_adap, &info);
- if (c->driver == NULL)
+ if (id == I2C_DRIVERID_UPD64031A ||
+ id == I2C_DRIVERID_UPD64083) {
+ unsigned short addrs[2] = { info.addr, I2C_CLIENT_END };
+
+ c = i2c_new_probed_device(&itv->i2c_adap, &info, addrs);
+ } else
+ c = i2c_new_device(&itv->i2c_adap, &info);
+ if (c && c->driver == NULL)
i2c_unregister_device(c);
- else
+ else if (c)
itv->i2c_clients[i] = c;
return itv->i2c_clients[i] ? 0 : -ENODEV;
}
@@ -679,7 +690,7 @@ static const char *ivtv_i2c_id_name(u32 id)
for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
if (hw_driverids[i] == id)
- return hw_drivernames[i];
+ return hw_devicenames[i];
return "unknown device";
}
@@ -690,7 +701,7 @@ static const char *ivtv_i2c_hw_name(u32 hw)
for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
if (1 << i == hw)
- return hw_drivernames[i];
+ return hw_devicenames[i];
return "unknown device";
}
@@ -792,7 +803,7 @@ int init_ivtv_i2c(struct ivtv *itv)
* same size and GPIO must be the last entry.
*/
if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
- ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) ||
+ ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
IVTV_ERR("Mismatched I2C hardware arrays\n");
diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
index 873296394..7101a0ea5 100644
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -38,7 +38,7 @@
#include <linux/dvb/audio.h>
#include <linux/i2c-id.h>
-u16 service2vbi(int type)
+u16 ivtv_service2vbi(int type)
{
switch (type) {
case V4L2_SLICED_TELETEXT_B:
@@ -88,7 +88,7 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
return 0;
}
-void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
{
u16 set = fmt->service_set;
int f, l;
@@ -115,7 +115,7 @@ static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
return set != 0;
}
-u16 get_service_set(struct v4l2_sliced_vbi_format *fmt)
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt)
{
int f, l;
u16 set = 0;
@@ -243,20 +243,31 @@ static int ivtv_validate_speed(int cur_speed, int new_speed)
int fact = new_speed < 0 ? -1 : 1;
int s;
- if (new_speed < 0) new_speed = -new_speed;
- if (cur_speed < 0) cur_speed = -cur_speed;
+ if (cur_speed == 0)
+ cur_speed = 1000;
+ if (new_speed < 0)
+ new_speed = -new_speed;
+ if (cur_speed < 0)
+ cur_speed = -cur_speed;
if (cur_speed <= new_speed) {
- if (new_speed > 1500) return fact * 2000;
- if (new_speed > 1000) return fact * 1500;
+ if (new_speed > 1500)
+ return fact * 2000;
+ if (new_speed > 1000)
+ return fact * 1500;
}
else {
- if (new_speed >= 2000) return fact * 2000;
- if (new_speed >= 1500) return fact * 1500;
- if (new_speed >= 1000) return fact * 1000;
- }
- if (new_speed == 0) return 1000;
- if (new_speed == 1 || new_speed == 1000) return fact * new_speed;
+ if (new_speed >= 2000)
+ return fact * 2000;
+ if (new_speed >= 1500)
+ return fact * 1500;
+ if (new_speed >= 1000)
+ return fact * 1000;
+ }
+ if (new_speed == 0)
+ return 1000;
+ if (new_speed == 1 || new_speed == 1000)
+ return fact * new_speed;
s = new_speed;
new_speed = 1000 / new_speed;
@@ -455,7 +466,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
}
- vbifmt->service_set = get_service_set(vbifmt);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
break;
}
@@ -470,12 +481,12 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
V4L2_SLICED_VBI_525;
- expand_service_set(vbifmt, itv->is_50hz);
+ ivtv_expand_service_set(vbifmt, itv->is_50hz);
break;
}
itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
- vbifmt->service_set = get_service_set(vbifmt);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
break;
}
case V4L2_BUF_TYPE_VBI_OUTPUT:
@@ -635,9 +646,9 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
if (vbifmt->service_set)
- expand_service_set(vbifmt, itv->is_50hz);
+ ivtv_expand_service_set(vbifmt, itv->is_50hz);
set = check_service_set(vbifmt, itv->is_50hz);
- vbifmt->service_set = get_service_set(vbifmt);
+ vbifmt->service_set = ivtv_get_service_set(vbifmt);
if (!set_fmt)
return 0;
@@ -747,9 +758,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
struct v4l2_capability *vcap = arg;
memset(vcap, 0, sizeof(*vcap));
- strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */
- strcpy(vcap->card, itv->card_name); /* card type */
- strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */
+ strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
vcap->version = IVTV_DRIVER_VERSION; /* version */
vcap->capabilities = itv->v4l2_cap; /* capabilities */
@@ -1023,7 +1034,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
ivtv_std_60hz : ivtv_std_50hz;
vs->index = idx;
vs->id = enum_stds[idx].std;
- strcpy(vs->name, enum_stds[idx].name);
+ strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
break;
}
@@ -1107,10 +1118,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
- strcpy(vt->name, "ivtv Radio Tuner");
+ strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_RADIO;
} else {
- strcpy(vt->name, "ivtv TV Tuner");
+ strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_ANALOG_TV;
}
break;
@@ -1644,6 +1655,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
+ printk("\n");
}
return ivtv_debug_ioctls(filp, cmd, arg);
@@ -1687,6 +1699,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
+ printk("\n");
}
return ivtv_v4l2_ioctls(itv, filp, cmd, arg);
@@ -1700,6 +1713,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
+ printk("\n");
}
return ivtv_control_ioctls(itv, cmd, arg);
diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.h b/linux/drivers/media/video/ivtv/ivtv-ioctl.h
index a03351b68..4e67f0ed1 100644
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -21,9 +21,9 @@
#ifndef IVTV_IOCTL_H
#define IVTV_IOCTL_H
-u16 service2vbi(int type);
-void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
-u16 get_service_set(struct v4l2_sliced_vbi_format *fmt);
+u16 ivtv_service2vbi(int type);
+void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c
index 0e417d860..d5ac766c1 100644
--- a/linux/drivers/media/video/ivtv/ivtv-irq.c
+++ b/linux/drivers/media/video/ivtv/ivtv-irq.c
@@ -237,14 +237,14 @@ static void dma_post(struct ivtv_stream *s)
struct ivtv_buffer *buf = NULL;
struct list_head *p;
u32 offset;
- u32 *u32buf;
+ __le32 *u32buf;
int x = 0;
IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
s->name, s->dma_offset);
list_for_each(p, &s->q_dma.list) {
buf = list_entry(p, struct ivtv_buffer, list);
- u32buf = (u32 *)buf->buf;
+ u32buf = (__le32 *)buf->buf;
/* Sync Buffer */
ivtv_buf_sync_for_cpu(s, buf);
@@ -390,7 +390,7 @@ static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
ivtv_stream_sync_for_device(s);
write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
- itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
add_timer(&itv->dma_timer);
}
@@ -406,7 +406,7 @@ static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
ivtv_stream_sync_for_device(s);
write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
- itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
add_timer(&itv->dma_timer);
}
@@ -450,7 +450,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
}
s->dma_xfer_cnt++;
- memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
s->sg_processing_size = s->sg_pending_size;
s->sg_pending_size = 0;
s->sg_processed = 0;
@@ -479,7 +479,7 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
s->dma_xfer_cnt++;
- memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
s->sg_processing_size = s->sg_pending_size;
s->sg_pending_size = 0;
s->sg_processed = 0;
diff --git a/linux/drivers/media/video/ivtv/ivtv-mailbox.c b/linux/drivers/media/video/ivtv/ivtv-mailbox.c
index 13a6c374d..1b5c0ac09 100644
--- a/linux/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/linux/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -177,7 +177,8 @@ static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int f
/* Sleep before a retry, if not atomic */
if (!(flags & API_NO_WAIT_MB)) {
- if (jiffies - then > msecs_to_jiffies(10*retries))
+ if (time_after(jiffies,
+ then + msecs_to_jiffies(10*retries)))
break;
ivtv_msleep_timeout(10, 0);
}
@@ -244,7 +245,9 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
data, then just return 0 as there is no need to issue this command again.
Just an optimization to prevent unnecessary use of mailboxes. */
if (itv->api_cache[cmd].last_jiffies &&
- jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
+ time_before(jiffies,
+ itv->api_cache[cmd].last_jiffies +
+ msecs_to_jiffies(1800000)) &&
!memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
itv->api_cache[cmd].last_jiffies = jiffies;
return 0;
@@ -299,7 +302,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
}
}
while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
- if (jiffies - then > api_timeout) {
+ if (time_after(jiffies, then + api_timeout)) {
IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
/* reset the mailbox, but it is likely too late already */
write_sync(0, &mbox->flags);
@@ -311,7 +314,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
else
ivtv_msleep_timeout(1, 0);
}
- if (jiffies - then > msecs_to_jiffies(100))
+ if (time_after(jiffies, then + msecs_to_jiffies(100)))
IVTV_DEBUG_WARN("%s took %u jiffies\n",
api_info[cmd].name,
jiffies_to_msecs(jiffies - then));
diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.c b/linux/drivers/media/video/ivtv/ivtv-queue.c
index 3e1deec67..71bd13e22 100644
--- a/linux/drivers/media/video/ivtv/ivtv-queue.c
+++ b/linux/drivers/media/video/ivtv/ivtv-queue.c
@@ -193,7 +193,7 @@ void ivtv_flush_queues(struct ivtv_stream *s)
int ivtv_stream_alloc(struct ivtv_stream *s)
{
struct ivtv *itv = s->itv;
- int SGsize = sizeof(struct ivtv_sg_element) * s->buffers;
+ int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers;
int i;
if (s->buffers == 0)
@@ -203,14 +203,14 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
s->dma != PCI_DMA_NONE ? "DMA " : "",
s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
- s->sg_pending = kzalloc(SGsize, GFP_KERNEL);
+ s->sg_pending = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
if (s->sg_pending == NULL) {
IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
return -ENOMEM;
}
s->sg_pending_size = 0;
- s->sg_processing = kzalloc(SGsize, GFP_KERNEL);
+ s->sg_processing = kzalloc(SGsize, GFP_KERNEL|__GFP_NOWARN);
if (s->sg_processing == NULL) {
IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
kfree(s->sg_pending);
@@ -219,7 +219,8 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
}
s->sg_processing_size = 0;
- s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL);
+ s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element),
+ GFP_KERNEL|__GFP_NOWARN);
if (s->sg_dma == NULL) {
IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
kfree(s->sg_pending);
@@ -235,11 +236,12 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
/* allocate stream buffers. Initially all buffers are in q_free. */
for (i = 0; i < s->buffers; i++) {
- struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL);
+ struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer),
+ GFP_KERNEL|__GFP_NOWARN);
if (buf == NULL)
break;
- buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL);
+ buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL|__GFP_NOWARN);
if (buf->buf == NULL) {
kfree(buf);
break;
diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c
index 24d98ecf3..01f546083 100644
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.c
@@ -44,23 +44,29 @@
#include "ivtv-streams.h"
static const struct file_operations ivtv_v4l2_enc_fops = {
- .owner = THIS_MODULE,
- .read = ivtv_v4l2_read,
- .write = ivtv_v4l2_write,
- .open = ivtv_v4l2_open,
- .ioctl = ivtv_v4l2_ioctl,
- .release = ivtv_v4l2_close,
- .poll = ivtv_v4l2_enc_poll,
+ .owner = THIS_MODULE,
+ .read = ivtv_v4l2_read,
+ .write = ivtv_v4l2_write,
+ .open = ivtv_v4l2_open,
+ .ioctl = ivtv_v4l2_ioctl,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+ .compat_ioctl = v4l_compat_ioctl32,
+#endif
+ .release = ivtv_v4l2_close,
+ .poll = ivtv_v4l2_enc_poll,
};
static const struct file_operations ivtv_v4l2_dec_fops = {
- .owner = THIS_MODULE,
- .read = ivtv_v4l2_read,
- .write = ivtv_v4l2_write,
- .open = ivtv_v4l2_open,
- .ioctl = ivtv_v4l2_ioctl,
- .release = ivtv_v4l2_close,
- .poll = ivtv_v4l2_dec_poll,
+ .owner = THIS_MODULE,
+ .read = ivtv_v4l2_read,
+ .write = ivtv_v4l2_write,
+ .open = ivtv_v4l2_open,
+ .ioctl = ivtv_v4l2_ioctl,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
+ .compat_ioctl = v4l_compat_ioctl32,
+#endif
+ .release = ivtv_v4l2_close,
+ .poll = ivtv_v4l2_dec_poll,
};
#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */
@@ -244,7 +250,7 @@ int ivtv_streams_setup(struct ivtv *itv)
return 0;
/* One or more streams could not be initialized. Clean 'em all up. */
- ivtv_streams_cleanup(itv);
+ ivtv_streams_cleanup(itv, 0);
return -ENOMEM;
}
@@ -304,12 +310,12 @@ int ivtv_streams_register(struct ivtv *itv)
return 0;
/* One or more streams could not be initialized. Clean 'em all up. */
- ivtv_streams_cleanup(itv);
+ ivtv_streams_cleanup(itv, 1);
return -ENOMEM;
}
/* Unregister v4l2 devices */
-void ivtv_streams_cleanup(struct ivtv *itv)
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister)
{
int type;
@@ -322,8 +328,11 @@ void ivtv_streams_cleanup(struct ivtv *itv)
continue;
ivtv_stream_free(&itv->streams[type]);
- /* Unregister device */
- video_unregister_device(vdev);
+ /* Unregister or release device */
+ if (unregister)
+ video_unregister_device(vdev);
+ else
+ video_device_release(vdev);
}
}
@@ -768,7 +777,8 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* wait 2s for EOS interrupt */
while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
- jiffies < then + msecs_to_jiffies (2000)) {
+ time_before(jiffies,
+ then + msecs_to_jiffies(2000))) {
schedule_timeout(msecs_to_jiffies(10));
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.h b/linux/drivers/media/video/ivtv/ivtv-streams.h
index 3d76a415f..a653a5136 100644
--- a/linux/drivers/media/video/ivtv/ivtv-streams.h
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.h
@@ -23,7 +23,7 @@
int ivtv_streams_setup(struct ivtv *itv);
int ivtv_streams_register(struct ivtv *itv);
-void ivtv_streams_cleanup(struct ivtv *itv);
+void ivtv_streams_cleanup(struct ivtv *itv, int unregister);
/* Capture related */
int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s);
diff --git a/linux/drivers/media/video/ivtv/ivtv-vbi.c b/linux/drivers/media/video/ivtv/ivtv-vbi.c
index c151bcf55..71798f0da 100644
--- a/linux/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/linux/drivers/media/video/ivtv/ivtv-vbi.c
@@ -169,7 +169,8 @@ static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
linemask[0] |= (1 << l);
else
linemask[1] |= (1 << (l - 32));
- dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id);
+ dst[sd + 12 + line * 43] =
+ ivtv_service2vbi(itv->vbi.sliced_data[i].id);
memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42);
line++;
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-version.h b/linux/drivers/media/video/ivtv/ivtv-version.h
index 0f1d4cc4b..442f43f11 100644
--- a/linux/drivers/media/video/ivtv/ivtv-version.h
+++ b/linux/drivers/media/video/ivtv/ivtv-version.h
@@ -22,7 +22,7 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 2
+#define IVTV_DRIVER_VERSION_MINOR 3
#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/linux/drivers/media/video/ivtv/ivtv-yuv.c b/linux/drivers/media/video/ivtv/ivtv-yuv.c
index 393d917cd..3092ff1d0 100644
--- a/linux/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/linux/drivers/media/video/ivtv/ivtv-yuv.c
@@ -908,7 +908,7 @@ static void ivtv_yuv_init(struct ivtv *itv)
}
/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
- yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL);
+ yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
if (yi->blanking_ptr) {
yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
} else {
@@ -1098,8 +1098,8 @@ void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
ivtv_yuv_next_free(itv);
/* Copy V4L2 parameters to an ivtv_dma_frame struct... */
- dma_args.y_source = 0L;
- dma_args.uv_source = 0L;
+ dma_args.y_source = NULL;
+ dma_args.uv_source = NULL;
dma_args.src.left = 0;
dma_args.src.top = 0;
dma_args.src.width = yi->v4l2_src_w;
@@ -1116,7 +1116,7 @@ void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
}
/* Attempt to dma a frame from a user buffer */
-int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
{
struct yuv_playback_info *yi = &itv->yuv_info;
struct ivtv_dma_frame dma_args;
diff --git a/linux/drivers/media/video/ivtv/ivtv-yuv.h b/linux/drivers/media/video/ivtv/ivtv-yuv.h
index 2fe5f1250..ca5173fbf 100644
--- a/linux/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/linux/drivers/media/video/ivtv/ivtv-yuv.h
@@ -35,7 +35,7 @@ extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
int ivtv_yuv_filter_check(struct ivtv *itv);
void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
-int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src);
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src);
void ivtv_yuv_frame_complete(struct ivtv *itv);
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
void ivtv_yuv_close(struct ivtv *itv);
diff --git a/linux/drivers/media/video/ivtv/ivtvfb.c b/linux/drivers/media/video/ivtv/ivtvfb.c
index 3b23fc05f..e8dbee443 100644
--- a/linux/drivers/media/video/ivtv/ivtvfb.c
+++ b/linux/drivers/media/video/ivtv/ivtvfb.c
@@ -367,6 +367,87 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
}
+static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *dst;
+ int err = 0;
+ unsigned long total_size;
+ struct ivtv *itv = (struct ivtv *) info->par;
+ unsigned long dma_offset =
+ IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
+ unsigned long dma_size;
+ u16 lead = 0, tail = 0;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
+ total_size = info->screen_size;
+
+ if (total_size == 0)
+ total_size = info->fix.smem_len;
+
+ if (p > total_size)
+ return -EFBIG;
+
+ if (count > total_size) {
+ err = -EFBIG;
+ count = total_size;
+ }
+
+ if (count + p > total_size) {
+ if (!err)
+ err = -ENOSPC;
+
+ count = total_size - p;
+ }
+
+ dst = (void __force *) (info->screen_base + p);
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ if (!access_ok(VERIFY_READ, buf, count)) {
+ IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
+ (unsigned long)buf);
+ err = -EFAULT;
+ }
+
+ if (!err) {
+ /* If transfer size > threshold and both src/dst
+ addresses are aligned, use DMA */
+ if (count >= 4096 && ((u32)buf & 3) == ((u32)dst & 3)) {
+ /* Odd address = can't DMA. Align */
+ if ((u32)dst & 3) {
+ lead = 4 - ((u32)dst & 3);
+ memcpy(dst, buf, lead);
+ buf += lead;
+ dst += lead;
+ }
+ /* DMA resolution is 32 bits */
+ if ((count - lead) & 3)
+ tail = (count - lead) & 3;
+ /* DMA the data */
+ dma_size = count - lead - tail;
+ err = ivtvfb_prep_dec_dma_to_device(itv,
+ p + lead + dma_offset, (void *)buf, dma_size);
+ dst += dma_size;
+ buf += dma_size;
+ /* Copy any leftover data */
+ if (tail)
+ memcpy(dst, buf, tail);
+ } else {
+ memcpy(dst, buf, count);
+ }
+ }
+
+ if (!err)
+ *ppos += count;
+
+ return (err) ? err : count;
+}
+
static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
DEFINE_WAIT(wait);
@@ -532,7 +613,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, "cx23415 TV out");
+ strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
fix->smem_start = oi->video_pbase;
fix->smem_len = oi->video_buffer_size;
fix->type = FB_TYPE_PACKED_PIXELS;
@@ -824,6 +905,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
static struct fb_ops ivtvfb_ops = {
.owner = THIS_MODULE,
+ .fb_write = ivtvfb_write,
.fb_check_var = ivtvfb_check_var,
.fb_set_par = ivtvfb_set_par,
.fb_setcolreg = ivtvfb_setcolreg,
@@ -948,7 +1030,8 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
}
/* Allocate the pseudo palette */
- oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ oi->ivtvfb_info.pseudo_palette =
+ kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
if (!oi->ivtvfb_info.pseudo_palette) {
IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
@@ -1056,7 +1139,8 @@ static int ivtvfb_init_card(struct ivtv *itv)
return -EBUSY;
}
- itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
+ itv->osd_info = kzalloc(sizeof(struct osd_info),
+ GFP_ATOMIC|__GFP_NOWARN);
if (itv->osd_info == NULL) {
IVTVFB_ERR("Failed to allocate memory for osd_info\n");
return -ENOMEM;
diff --git a/linux/drivers/media/video/m52790.c b/linux/drivers/media/video/m52790.c
index fa49d8f3e..77536ccfc 100644
--- a/linux/drivers/media/video/m52790.c
+++ b/linux/drivers/media/video/m52790.c
@@ -140,7 +140,8 @@ static int m52790_command(struct i2c_client *client, unsigned int cmd,
/* i2c implementation */
-static int m52790_probe(struct i2c_client *client)
+static int m52790_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct m52790_state *state;
@@ -148,8 +149,10 @@ static int m52790_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "m52790");
+#endif
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -172,12 +175,23 @@ static int m52790_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id m52790_id[] = {
+ { "m52790", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, m52790_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "m52790",
.driverid = I2C_DRIVERID_M52790,
.command = m52790_command,
.probe = m52790_probe,
.remove = m52790_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = m52790_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/meye.c b/linux/drivers/media/video/meye.c
index f96330be7..07295afff 100644
--- a/linux/drivers/media/video/meye.c
+++ b/linux/drivers/media/video/meye.c
@@ -43,15 +43,10 @@
#include <linux/meye.h>
MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
-MODULE_DESCRIPTION("v4l/v4l2 driver for the MotionEye camera");
+MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera");
MODULE_LICENSE("GPL");
MODULE_VERSION(MEYE_DRIVER_VERSION);
-/* force usage of V4L1 API */
-static int forcev4l1; /* = 0 */
-module_param(forcev4l1, int, 0644);
-MODULE_PARM_DESC(forcev4l1, "force use of V4L1 instead of V4L2");
-
/* number of grab buffers */
static unsigned int gbuffers = 2;
module_param(gbuffers, int, 0444);
@@ -881,803 +876,737 @@ static int meye_release(struct inode *inode, struct file *file)
return 0;
}
-static int meye_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int meyeioc_g_params(struct meye_params *p)
{
- switch (cmd) {
+ *p = meye.params;
+ return 0;
+}
- case VIDIOCGCAP: {
- struct video_capability *b = arg;
- strcpy(b->name,meye.video_dev->name);
- b->type = VID_TYPE_CAPTURE;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = 640;
- b->maxheight = 480;
- b->minwidth = 320;
- b->minheight = 240;
- break;
- }
+static int meyeioc_s_params(struct meye_params *jp)
+{
+ if (jp->subsample > 1)
+ return -EINVAL;
- case VIDIOCGCHAN: {
- struct video_channel *v = arg;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- if (v->channel != 0)
- return -EINVAL;
- strcpy(v->name,"Camera");
- break;
- }
+ if (jp->quality > 10)
+ return -EINVAL;
- case VIDIOCSCHAN: {
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- break;
- }
+ if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63)
+ return -EINVAL;
- case VIDIOCGPICT: {
- struct video_picture *p = arg;
- *p = meye.picture;
- break;
- }
+ if (jp->framerate > 31)
+ return -EINVAL;
- case VIDIOCSPICT: {
- struct video_picture *p = arg;
- if (p->depth != 16)
- return -EINVAL;
- if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV)
- return -EINVAL;
- mutex_lock(&meye.lock);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS,
- p->brightness >> 10);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE,
- p->hue >> 10);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR,
- p->colour >> 10);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST,
- p->contrast >> 10);
- meye.picture = *p;
- mutex_unlock(&meye.lock);
- break;
- }
+ mutex_lock(&meye.lock);
- case VIDIOCSYNC: {
- int *i = arg;
- int unused;
+ if (meye.params.subsample != jp->subsample ||
+ meye.params.quality != jp->quality)
+ mchip_hic_stop(); /* need restart */
+
+ meye.params = *jp;
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
+ meye.params.sharpness);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
+ meye.params.agc);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
+ meye.params.picture);
+ mutex_unlock(&meye.lock);
- if (*i < 0 || *i >= gbuffers)
- return -EINVAL;
+ return 0;
+}
- mutex_lock(&meye.lock);
+static int meyeioc_qbuf_capt(int *nb)
+{
+ if (!meye.grab_fbuffer)
+ return -EINVAL;
- switch (meye.grab_buffer[*i].state) {
+ if (*nb >= gbuffers)
+ return -EINVAL;
- case MEYE_BUF_UNUSED:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- case MEYE_BUF_USING:
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
- if (wait_event_interruptible(meye.proc_list,
- (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
- mutex_unlock(&meye.lock);
- return -EINTR;
- }
- /* fall through */
- case MEYE_BUF_DONE:
- meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
- kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
- }
- mutex_unlock(&meye.lock);
- break;
+ if (*nb < 0) {
+ /* stop capture */
+ mchip_hic_stop();
+ return 0;
}
- case VIDIOCMCAPTURE: {
- struct video_mmap *vm = arg;
- int restart = 0;
-
- if (vm->frame >= gbuffers || vm->frame < 0)
- return -EINVAL;
- if (vm->format != VIDEO_PALETTE_YUV422 && vm->format != VIDEO_PALETTE_YUYV)
- return -EINVAL;
- if (vm->height * vm->width * 2 > gbufsize)
- return -EINVAL;
- if (!meye.grab_fbuffer)
- return -EINVAL;
- if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED)
- return -EBUSY;
-
- mutex_lock(&meye.lock);
- if (vm->width == 640 && vm->height == 480) {
- if (meye.params.subsample) {
- meye.params.subsample = 0;
- restart = 1;
- }
- } else if (vm->width == 320 && vm->height == 240) {
- if (!meye.params.subsample) {
- meye.params.subsample = 1;
- restart = 1;
- }
- } else {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
+ if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
+ return -EBUSY;
- if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT)
- mchip_continuous_start();
- meye.grab_buffer[vm->frame].state = MEYE_BUF_USING;
- kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int));
- mutex_unlock(&meye.lock);
- break;
- }
+ mutex_lock(&meye.lock);
- case VIDIOCGMBUF: {
- struct video_mbuf *vm = arg;
- int i;
+ if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
+ mchip_cont_compression_start();
- memset(vm, 0 , sizeof(*vm));
- vm->size = gbufsize * gbuffers;
- vm->frames = gbuffers;
- for (i = 0; i < gbuffers; i++)
- vm->offsets[i] = i * gbufsize;
- break;
- }
+ meye.grab_buffer[*nb].state = MEYE_BUF_USING;
+ kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
+ mutex_unlock(&meye.lock);
- case MEYEIOC_G_PARAMS: {
- struct meye_params *p = arg;
- *p = meye.params;
- break;
- }
+ return 0;
+}
- case MEYEIOC_S_PARAMS: {
- struct meye_params *jp = arg;
- if (jp->subsample > 1)
- return -EINVAL;
- if (jp->quality > 10)
- return -EINVAL;
- if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63)
- return -EINVAL;
- if (jp->framerate > 31)
- return -EINVAL;
- mutex_lock(&meye.lock);
- if (meye.params.subsample != jp->subsample ||
- meye.params.quality != jp->quality)
- mchip_hic_stop(); /* need restart */
- meye.params = *jp;
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
- meye.params.sharpness);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
- meye.params.agc);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
- meye.params.picture);
- mutex_unlock(&meye.lock);
- break;
- }
+static int meyeioc_sync(struct file *file, void *fh, int *i)
+{
+ int unused;
- case MEYEIOC_QBUF_CAPT: {
- int *nb = arg;
-
- if (!meye.grab_fbuffer)
- return -EINVAL;
- if (*nb >= gbuffers)
- return -EINVAL;
- if (*nb < 0) {
- /* stop capture */
- mchip_hic_stop();
- return 0;
- }
- if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
- return -EBUSY;
- mutex_lock(&meye.lock);
- if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
- mchip_cont_compression_start();
- meye.grab_buffer[*nb].state = MEYE_BUF_USING;
- kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
+ if (*i < 0 || *i >= gbuffers)
+ return -EINVAL;
+
+ mutex_lock(&meye.lock);
+ switch (meye.grab_buffer[*i].state) {
+
+ case MEYE_BUF_UNUSED:
mutex_unlock(&meye.lock);
- break;
+ return -EINVAL;
+ case MEYE_BUF_USING:
+ if (file->f_flags & O_NONBLOCK) {
+ mutex_unlock(&meye.lock);
+ return -EAGAIN;
+ }
+ if (wait_event_interruptible(meye.proc_list,
+ (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
+ mutex_unlock(&meye.lock);
+ return -EINTR;
+ }
+ /* fall through */
+ case MEYE_BUF_DONE:
+ meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
+ kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
}
+ *i = meye.grab_buffer[*i].size;
+ mutex_unlock(&meye.lock);
+ return 0;
+}
- case MEYEIOC_SYNC: {
- int *i = arg;
- int unused;
+static int meyeioc_stillcapt(void)
+{
+ if (!meye.grab_fbuffer)
+ return -EINVAL;
- if (*i < 0 || *i >= gbuffers)
- return -EINVAL;
+ if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+ return -EBUSY;
- mutex_lock(&meye.lock);
- switch (meye.grab_buffer[*i].state) {
+ mutex_lock(&meye.lock);
+ meye.grab_buffer[0].state = MEYE_BUF_USING;
+ mchip_take_picture();
- case MEYE_BUF_UNUSED:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- case MEYE_BUF_USING:
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
- if (wait_event_interruptible(meye.proc_list,
- (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
- mutex_unlock(&meye.lock);
- return -EINTR;
- }
- /* fall through */
- case MEYE_BUF_DONE:
- meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
- kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
- }
- *i = meye.grab_buffer[*i].size;
- mutex_unlock(&meye.lock);
- break;
- }
+ mchip_get_picture(meye.grab_fbuffer,
+ mchip_hsize() * mchip_vsize() * 2);
- case MEYEIOC_STILLCAPT: {
+ meye.grab_buffer[0].state = MEYE_BUF_DONE;
+ mutex_unlock(&meye.lock);
- if (!meye.grab_fbuffer)
- return -EINVAL;
- if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
- return -EBUSY;
- mutex_lock(&meye.lock);
- meye.grab_buffer[0].state = MEYE_BUF_USING;
+ return 0;
+}
+
+static int meyeioc_stilljcapt(int *len)
+{
+ if (!meye.grab_fbuffer)
+ return -EINVAL;
+
+ if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+ return -EBUSY;
+
+ mutex_lock(&meye.lock);
+ meye.grab_buffer[0].state = MEYE_BUF_USING;
+ *len = -1;
+
+ while (*len == -1) {
mchip_take_picture();
- mchip_get_picture(
- meye.grab_fbuffer,
- mchip_hsize() * mchip_vsize() * 2);
- meye.grab_buffer[0].state = MEYE_BUF_DONE;
- mutex_unlock(&meye.lock);
- break;
+ *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
}
- case MEYEIOC_STILLJCAPT: {
- int *len = arg;
-
- if (!meye.grab_fbuffer)
- return -EINVAL;
- if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
- return -EBUSY;
- mutex_lock(&meye.lock);
- meye.grab_buffer[0].state = MEYE_BUF_USING;
- *len = -1;
- while (*len == -1) {
- mchip_take_picture();
- *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
- }
- meye.grab_buffer[0].state = MEYE_BUF_DONE;
- mutex_unlock(&meye.lock);
- break;
- }
+ meye.grab_buffer[0].state = MEYE_BUF_DONE;
+ mutex_unlock(&meye.lock);
+ return 0;
+}
- case VIDIOC_QUERYCAP: {
- struct v4l2_capability *cap = arg;
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, "meye");
+ strcpy(cap->card, "meye");
+ sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
- if (forcev4l1)
- return -EINVAL;
+ cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
+ MEYE_DRIVER_MINORVERSION;
- memset(cap, 0, sizeof(*cap));
- strcpy(cap->driver, "meye");
- strcpy(cap->card, "meye");
- sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
- cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
- MEYE_DRIVER_MINORVERSION;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING;
- break;
- }
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
- case VIDIOC_ENUMINPUT: {
- struct v4l2_input *i = arg;
+ memset(i, 0, sizeof(*i));
+ i->index = 0;
+ strcpy(i->name, "Camera");
+ i->type = V4L2_INPUT_TYPE_CAMERA;
- if (i->index != 0)
- return -EINVAL;
- memset(i, 0, sizeof(*i));
- i->index = 0;
- strcpy(i->name, "Camera");
- i->type = V4L2_INPUT_TYPE_CAMERA;
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *c)
+{
+ switch (c->id) {
+
+ case V4L2_CID_BRIGHTNESS:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Brightness");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+ c->flags = 0;
+ break;
+ case V4L2_CID_HUE:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Hue");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+ c->flags = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Contrast");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+ c->flags = 0;
+ break;
+ case V4L2_CID_SATURATION:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Saturation");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+ c->flags = 0;
+ break;
+ case V4L2_CID_AGC:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Agc");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 48;
+ c->flags = 0;
break;
+ case V4L2_CID_MEYE_SHARPNESS:
+ case V4L2_CID_SHARPNESS:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Sharpness");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+
+ /* Continue to report legacy private SHARPNESS ctrl but
+ * say it is disabled in preference to ctrl in the spec
+ */
+ c->flags = (c->id == V4L2_CID_SHARPNESS) ? 0 :
+ V4L2_CTRL_FLAG_DISABLED;
+ break;
+ case V4L2_CID_PICTURE:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Picture");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 0;
+ c->flags = 0;
+ break;
+ case V4L2_CID_JPEGQUAL:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "JPEG quality");
+ c->minimum = 0;
+ c->maximum = 10;
+ c->step = 1;
+ c->default_value = 8;
+ c->flags = 0;
+ break;
+ case V4L2_CID_FRAMERATE:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Framerate");
+ c->minimum = 0;
+ c->maximum = 31;
+ c->step = 1;
+ c->default_value = 0;
+ c->flags = 0;
+ break;
+ default:
+ return -EINVAL;
}
- case VIDIOC_G_INPUT: {
- int *i = arg;
+ return 0;
+}
- *i = 0;
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+ mutex_lock(&meye.lock);
+ switch (c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
+ meye.picture.brightness = c->value << 10;
+ break;
+ case V4L2_CID_HUE:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
+ meye.picture.hue = c->value << 10;
+ break;
+ case V4L2_CID_CONTRAST:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
+ meye.picture.contrast = c->value << 10;
+ break;
+ case V4L2_CID_SATURATION:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
+ meye.picture.colour = c->value << 10;
+ break;
+ case V4L2_CID_AGC:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
+ meye.params.agc = c->value;
+ break;
+ case V4L2_CID_SHARPNESS:
+ case V4L2_CID_MEYE_SHARPNESS:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
+ meye.params.sharpness = c->value;
+ break;
+ case V4L2_CID_PICTURE:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
+ meye.params.picture = c->value;
+ break;
+ case V4L2_CID_JPEGQUAL:
+ meye.params.quality = c->value;
+ break;
+ case V4L2_CID_FRAMERATE:
+ meye.params.framerate = c->value;
break;
+ default:
+ mutex_unlock(&meye.lock);
+ return -EINVAL;
}
+ mutex_unlock(&meye.lock);
- case VIDIOC_S_INPUT: {
- int *i = arg;
+ return 0;
+}
- if (*i != 0)
- return -EINVAL;
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+ mutex_lock(&meye.lock);
+ switch (c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ c->value = meye.picture.brightness >> 10;
+ break;
+ case V4L2_CID_HUE:
+ c->value = meye.picture.hue >> 10;
+ break;
+ case V4L2_CID_CONTRAST:
+ c->value = meye.picture.contrast >> 10;
+ break;
+ case V4L2_CID_SATURATION:
+ c->value = meye.picture.colour >> 10;
+ break;
+ case V4L2_CID_AGC:
+ c->value = meye.params.agc;
+ break;
+ case V4L2_CID_SHARPNESS:
+ case V4L2_CID_MEYE_SHARPNESS:
+ c->value = meye.params.sharpness;
break;
+ case V4L2_CID_PICTURE:
+ c->value = meye.params.picture;
+ break;
+ case V4L2_CID_JPEGQUAL:
+ c->value = meye.params.quality;
+ break;
+ case V4L2_CID_FRAMERATE:
+ c->value = meye.params.framerate;
+ break;
+ default:
+ mutex_unlock(&meye.lock);
+ return -EINVAL;
}
+ mutex_unlock(&meye.lock);
- case VIDIOC_QUERYCTRL: {
- struct v4l2_queryctrl *c = arg;
+ return 0;
+}
- switch (c->id) {
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index > 1)
+ return -EINVAL;
- case V4L2_CID_BRIGHTNESS:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Brightness");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_HUE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Hue");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_CONTRAST:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Contrast");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_SATURATION:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Saturation");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_AGC:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Agc");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 48;
- c->flags = 0;
- break;
- case V4L2_CID_MEYE_SHARPNESS:
- case V4L2_CID_SHARPNESS:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Sharpness");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
-
- /* Continue to report legacy private SHARPNESS ctrl but
- * say it is disabled in preference to ctrl in the spec
- */
- c->flags = (c->id == V4L2_CID_SHARPNESS) ? 0 :
- V4L2_CTRL_FLAG_DISABLED;
- break;
- case V4L2_CID_PICTURE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Picture");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 0;
- c->flags = 0;
- break;
- case V4L2_CID_JPEGQUAL:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "JPEG quality");
- c->minimum = 0;
- c->maximum = 10;
- c->step = 1;
- c->default_value = 8;
- c->flags = 0;
- break;
- case V4L2_CID_FRAMERATE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Framerate");
- c->minimum = 0;
- c->maximum = 31;
- c->step = 1;
- c->default_value = 0;
- c->flags = 0;
- break;
- default:
- return -EINVAL;
- }
- break;
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (f->index == 0) {
+ /* standard YUV 422 capture */
+ memset(f, 0, sizeof(*f));
+ f->index = 0;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = 0;
+ strcpy(f->description, "YUV422");
+ f->pixelformat = V4L2_PIX_FMT_YUYV;
+ } else {
+ /* compressed MJPEG capture */
+ memset(f, 0, sizeof(*f));
+ f->index = 1;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strcpy(f->description, "MJPEG");
+ f->pixelformat = V4L2_PIX_FMT_MJPEG;
}
- case VIDIOC_S_CTRL: {
- struct v4l2_control *c = arg;
+ return 0;
+}
- mutex_lock(&meye.lock);
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
- meye.picture.brightness = c->value << 10;
- break;
- case V4L2_CID_HUE:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
- meye.picture.hue = c->value << 10;
- break;
- case V4L2_CID_CONTRAST:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
- meye.picture.contrast = c->value << 10;
- break;
- case V4L2_CID_SATURATION:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
- meye.picture.colour = c->value << 10;
- break;
- case V4L2_CID_AGC:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
- meye.params.agc = c->value;
- break;
- case V4L2_CID_SHARPNESS:
- case V4L2_CID_MEYE_SHARPNESS:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
- meye.params.sharpness = c->value;
- break;
- case V4L2_CID_PICTURE:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
- meye.params.picture = c->value;
- break;
- case V4L2_CID_JPEGQUAL:
- meye.params.quality = c->value;
- break;
- case V4L2_CID_FRAMERATE:
- meye.params.framerate = c->value;
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- mutex_unlock(&meye.lock);
- break;
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+ f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+ return -EINVAL;
+
+ if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+ f->fmt.pix.field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ if (f->fmt.pix.width <= 320) {
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ } else {
+ f->fmt.pix.width = 640;
+ f->fmt.pix.height = 480;
}
- case VIDIOC_G_CTRL: {
- struct v4l2_control *c = arg;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.priv = 0;
- mutex_lock(&meye.lock);
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- c->value = meye.picture.brightness >> 10;
- break;
- case V4L2_CID_HUE:
- c->value = meye.picture.hue >> 10;
- break;
- case V4L2_CID_CONTRAST:
- c->value = meye.picture.contrast >> 10;
- break;
- case V4L2_CID_SATURATION:
- c->value = meye.picture.colour >> 10;
- break;
- case V4L2_CID_AGC:
- c->value = meye.params.agc;
- break;
- case V4L2_CID_SHARPNESS:
- case V4L2_CID_MEYE_SHARPNESS:
- c->value = meye.params.sharpness;
- break;
- case V4L2_CID_PICTURE:
- c->value = meye.params.picture;
- break;
- case V4L2_CID_JPEGQUAL:
- c->value = meye.params.quality;
- break;
- case V4L2_CID_FRAMERATE:
- c->value = meye.params.framerate;
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- mutex_unlock(&meye.lock);
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ switch (meye.mchip_mode) {
+ case MCHIP_HIC_MODE_CONT_OUT:
+ default:
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ break;
+ case MCHIP_HIC_MODE_CONT_COMP:
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
break;
}
- case VIDIOC_ENUM_FMT: {
- struct v4l2_fmtdesc *f = arg;
-
- if (f->index > 1)
- return -EINVAL;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->index == 0) {
- /* standard YUV 422 capture */
- memset(f, 0, sizeof(*f));
- f->index = 0;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->flags = 0;
- strcpy(f->description, "YUV422");
- f->pixelformat = V4L2_PIX_FMT_YUYV;
- } else {
- /* compressed MJPEG capture */
- memset(f, 0, sizeof(*f));
- f->index = 1;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "MJPEG");
- f->pixelformat = V4L2_PIX_FMT_MJPEG;
- }
- break;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.width = mchip_hsize();
+ f->fmt.pix.height = mchip_vsize();
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.priv = 0;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+ f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+ return -EINVAL;
+
+ if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+ f->fmt.pix.field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ mutex_lock(&meye.lock);
+
+ if (f->fmt.pix.width <= 320) {
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ meye.params.subsample = 1;
+ } else {
+ f->fmt.pix.width = 640;
+ f->fmt.pix.height = 480;
+ meye.params.subsample = 0;
}
- case VIDIOC_TRY_FMT: {
- struct v4l2_format *f = arg;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
- f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- if (f->fmt.pix.width <= 320) {
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- } else {
- f->fmt.pix.width = 640;
- f->fmt.pix.height = 480;
- }
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
+ break;
+ case V4L2_PIX_FMT_MJPEG:
+ meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
break;
}
- case VIDIOC_G_FMT: {
- struct v4l2_format *f = arg;
+ mutex_unlock(&meye.lock);
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.priv = 0;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- switch (meye.mchip_mode) {
- case MCHIP_HIC_MODE_CONT_OUT:
- default:
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- break;
- case MCHIP_HIC_MODE_CONT_COMP:
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
- break;
- }
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = mchip_hsize();
- f->fmt.pix.height = mchip_vsize();
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
- break;
- }
+ return 0;
+}
- case VIDIOC_S_FMT: {
- struct v4l2_format *f = arg;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
- f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- mutex_lock(&meye.lock);
- if (f->fmt.pix.width <= 320) {
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- meye.params.subsample = 1;
- } else {
- f->fmt.pix.width = 640;
- f->fmt.pix.height = 480;
- meye.params.subsample = 0;
- }
- switch (f->fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_YUYV:
- meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
- break;
- case V4L2_PIX_FMT_MJPEG:
- meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
- break;
- }
- mutex_unlock(&meye.lock);
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *req)
+{
+ int i;
- break;
- }
+ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
- case VIDIOC_REQBUFS: {
- struct v4l2_requestbuffers *req = arg;
- int i;
+ if (req->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (req->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- if (meye.grab_fbuffer && req->count == gbuffers) {
- /* already allocated, no modifications */
- break;
- }
- mutex_lock(&meye.lock);
- if (meye.grab_fbuffer) {
- for (i = 0; i < gbuffers; i++)
- if (meye.vma_use_count[i]) {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
- meye.grab_fbuffer = NULL;
- }
- gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
- req->count = gbuffers;
- meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
- if (!meye.grab_fbuffer) {
- printk(KERN_ERR "meye: v4l framebuffer allocation"
- " failed\n");
- mutex_unlock(&meye.lock);
- return -ENOMEM;
- }
- for (i = 0; i < gbuffers; i++)
- meye.vma_use_count[i] = 0;
- mutex_unlock(&meye.lock);
- break;
+ if (meye.grab_fbuffer && req->count == gbuffers) {
+ /* already allocated, no modifications */
+ return 0;
}
- case VIDIOC_QUERYBUF: {
- struct v4l2_buffer *buf = arg;
- int index = buf->index;
-
- if (index < 0 || index >= gbuffers)
- return -EINVAL;
- memset(buf, 0, sizeof(*buf));
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf->index = index;
- buf->bytesused = meye.grab_buffer[index].size;
- buf->flags = V4L2_BUF_FLAG_MAPPED;
- if (meye.grab_buffer[index].state == MEYE_BUF_USING)
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
- if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
- buf->flags |= V4L2_BUF_FLAG_DONE;
- buf->field = V4L2_FIELD_NONE;
- buf->timestamp = meye.grab_buffer[index].timestamp;
- buf->sequence = meye.grab_buffer[index].sequence;
- buf->memory = V4L2_MEMORY_MMAP;
- buf->m.offset = index * gbufsize;
- buf->length = gbufsize;
- break;
+ mutex_lock(&meye.lock);
+ if (meye.grab_fbuffer) {
+ for (i = 0; i < gbuffers; i++)
+ if (meye.vma_use_count[i]) {
+ mutex_unlock(&meye.lock);
+ return -EINVAL;
+ }
+ rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
+ meye.grab_fbuffer = NULL;
}
- case VIDIOC_QBUF: {
- struct v4l2_buffer *buf = arg;
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- if (buf->index < 0 || buf->index >= gbuffers)
- return -EINVAL;
- if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
- return -EINVAL;
- mutex_lock(&meye.lock);
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
- buf->flags &= ~V4L2_BUF_FLAG_DONE;
- meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
- kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
+ gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
+ req->count = gbuffers;
+ meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
+
+ if (!meye.grab_fbuffer) {
+ printk(KERN_ERR "meye: v4l framebuffer allocation"
+ " failed\n");
mutex_unlock(&meye.lock);
- break;
+ return -ENOMEM;
}
- case VIDIOC_DQBUF: {
- struct v4l2_buffer *buf = arg;
- int reqnr;
+ for (i = 0; i < gbuffers; i++)
+ meye.vma_use_count[i] = 0;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
+ mutex_unlock(&meye.lock);
- mutex_lock(&meye.lock);
- if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
- if (wait_event_interruptible(meye.proc_list,
- kfifo_len(meye.doneq) != 0) < 0) {
- mutex_unlock(&meye.lock);
- return -EINTR;
- }
- if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
- sizeof(int))) {
- mutex_unlock(&meye.lock);
- return -EBUSY;
- }
- if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- buf->index = reqnr;
- buf->bytesused = meye.grab_buffer[reqnr].size;
- buf->flags = V4L2_BUF_FLAG_MAPPED;
- buf->field = V4L2_FIELD_NONE;
- buf->timestamp = meye.grab_buffer[reqnr].timestamp;
- buf->sequence = meye.grab_buffer[reqnr].sequence;
- buf->memory = V4L2_MEMORY_MMAP;
- buf->m.offset = reqnr * gbufsize;
- buf->length = gbufsize;
- meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
+ return 0;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ int index = buf->index;
+
+ if (index < 0 || index >= gbuffers)
+ return -EINVAL;
+
+ memset(buf, 0, sizeof(*buf));
+
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->index = index;
+ buf->bytesused = meye.grab_buffer[index].size;
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+
+ if (meye.grab_buffer[index].state == MEYE_BUF_USING)
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+
+ if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
+ buf->flags |= V4L2_BUF_FLAG_DONE;
+
+ buf->field = V4L2_FIELD_NONE;
+ buf->timestamp = meye.grab_buffer[index].timestamp;
+ buf->sequence = meye.grab_buffer[index].sequence;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = index * gbufsize;
+ buf->length = gbufsize;
+
+ return 0;
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if (buf->index < 0 || buf->index >= gbuffers)
+ return -EINVAL;
+
+ if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
+ return -EINVAL;
+
+ mutex_lock(&meye.lock);
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+ meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
+ kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
+ mutex_unlock(&meye.lock);
+
+ return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ int reqnr;
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ mutex_lock(&meye.lock);
+
+ if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
mutex_unlock(&meye.lock);
- break;
+ return -EAGAIN;
}
- case VIDIOC_STREAMON: {
- mutex_lock(&meye.lock);
- switch (meye.mchip_mode) {
- case MCHIP_HIC_MODE_CONT_OUT:
- mchip_continuous_start();
- break;
- case MCHIP_HIC_MODE_CONT_COMP:
- mchip_cont_compression_start();
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
+ if (wait_event_interruptible(meye.proc_list,
+ kfifo_len(meye.doneq) != 0) < 0) {
mutex_unlock(&meye.lock);
- break;
+ return -EINTR;
}
- case VIDIOC_STREAMOFF: {
- int i;
+ if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
+ sizeof(int))) {
+ mutex_unlock(&meye.lock);
+ return -EBUSY;
+ }
- mutex_lock(&meye.lock);
- mchip_hic_stop();
- kfifo_reset(meye.grabq);
- kfifo_reset(meye.doneq);
- for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
- meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+ if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
mutex_unlock(&meye.lock);
- break;
+ return -EINVAL;
}
- /*
- * XXX what about private snapshot ioctls ?
- * Do they need to be converted to V4L2 ?
- */
+ buf->index = reqnr;
+ buf->bytesused = meye.grab_buffer[reqnr].size;
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->field = V4L2_FIELD_NONE;
+ buf->timestamp = meye.grab_buffer[reqnr].timestamp;
+ buf->sequence = meye.grab_buffer[reqnr].sequence;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = reqnr * gbufsize;
+ buf->length = gbufsize;
+ meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
+ mutex_unlock(&meye.lock);
+
+ return 0;
+}
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ mutex_lock(&meye.lock);
+
+ switch (meye.mchip_mode) {
+ case MCHIP_HIC_MODE_CONT_OUT:
+ mchip_continuous_start();
+ break;
+ case MCHIP_HIC_MODE_CONT_COMP:
+ mchip_cont_compression_start();
+ break;
default:
- return -ENOIOCTLCMD;
+ mutex_unlock(&meye.lock);
+ return -EINVAL;
}
+ mutex_unlock(&meye.lock);
+
return 0;
}
-static int meye_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
{
- return video_usercopy(inode, file, cmd, arg, meye_do_ioctl);
+ mutex_lock(&meye.lock);
+ mchip_hic_stop();
+ kfifo_reset(meye.grabq);
+ kfifo_reset(meye.doneq);
+
+ for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
+ meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+
+ mutex_unlock(&meye.lock);
+ return 0;
+}
+
+static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+ switch (cmd) {
+ case MEYEIOC_G_PARAMS:
+ return meyeioc_g_params((struct meye_params *) arg);
+
+ case MEYEIOC_S_PARAMS:
+ return meyeioc_s_params((struct meye_params *) arg);
+
+ case MEYEIOC_QBUF_CAPT:
+ return meyeioc_qbuf_capt((int *) arg);
+
+ case MEYEIOC_SYNC:
+ return meyeioc_sync(file, fh, (int *) arg);
+
+ case MEYEIOC_STILLCAPT:
+ return meyeioc_stillcapt();
+
+ case MEYEIOC_STILLJCAPT:
+ return meyeioc_stilljcapt((int *) arg);
+
+ default:
+ return -EINVAL;
+ }
+
}
static unsigned int meye_poll(struct file *file, poll_table *wait)
@@ -1765,7 +1694,7 @@ static const struct file_operations meye_fops = {
.open = meye_open,
.release = meye_release,
.mmap = meye_mmap,
- .ioctl = meye_ioctl,
+ .ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
#endif
@@ -1780,6 +1709,24 @@ static struct video_device meye_template = {
.fops = &meye_fops,
.release = video_device_release,
.minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_default = vidioc_default,
};
#ifdef CONFIG_PM
diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c
index ef780ed60..5ea4fd801 100644
--- a/linux/drivers/media/video/msp3400-driver.c
+++ b/linux/drivers/media/video/msp3400-driver.c
@@ -410,7 +410,7 @@ int msp_sleep(struct msp_state *state, int timeout)
}
/* ------------------------------------------------------------------------ */
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode)
{
if (rxsubchans == V4L2_TUNER_SUB_MONO)
@@ -558,7 +558,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
case VIDIOCGAUDIO:
{
struct video_audio *va = arg;
@@ -849,7 +849,7 @@ static int msp_resume(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-static int msp_probe(struct i2c_client *client)
+static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct msp_state *state;
int (*thread_func)(void *data) = NULL;
@@ -859,7 +859,12 @@ static int msp_probe(struct i2c_client *client)
int msp_product, msp_prod_hi, msp_prod_lo;
int msp_rom;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "msp3400");
+#else
+ if (!id)
+ strlcpy(client->name, "msp3400", sizeof(client->name));
+#endif
if (msp_reset(client) == -1) {
v4l_dbg(1, msp_debug, client, "msp3400 not found\n");
@@ -912,9 +917,11 @@ static int msp_probe(struct i2c_client *client)
msp_revision = (state->rev1 & 0x0f) + '@';
msp_hard = ((state->rev1 >> 8) & 0xff) + '@';
msp_rom = state->rev2 & 0x1f;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
msp_family, msp_product,
msp_revision, msp_hard, msp_rom);
+#endif
/* Rev B=2, C=3, D=4, G=7 */
state->ident = msp_family * 10000 + 4000 + msp_product * 10 +
msp_revision - '@';
@@ -979,7 +986,9 @@ static int msp_probe(struct i2c_client *client)
}
/* hello world :-) */
- v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
+ v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n",
+ msp_family, msp_product,
+ msp_revision, msp_hard, msp_rom,
client->addr << 1, client->adapter->name);
v4l_info(client, "%s ", client->name);
if (state->has_nicam && state->has_radio)
@@ -1057,6 +1066,14 @@ static int msp_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id msp_id[] = {
+ { "msp3400", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, msp_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "msp3400",
.driverid = I2C_DRIVERID_MSP3400,
@@ -1065,6 +1082,9 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.remove = msp_remove,
.suspend = msp_suspend,
.resume = msp_resume,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = msp_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/mt20xx.c b/linux/drivers/media/video/mt20xx.c
deleted file mode 100644
index d2c281aeb..000000000
--- a/linux/drivers/media/video/mt20xx.c
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * i2c tv tuner chip device driver
- * controls microtune tuners, mt2032 + mt2050 at the moment.
- *
- * This "mt20xx" module was split apart from the original "tuner" module.
- */
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include "compat.h"
-#include <linux/videodev.h>
-#include "tuner-i2c.h"
-#include "mt20xx.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-/* ---------------------------------------------------------------------- */
-
-static unsigned int optimize_vco = 1;
-module_param(optimize_vco, int, 0644);
-
-static unsigned int tv_antenna = 1;
-module_param(tv_antenna, int, 0644);
-
-static unsigned int radio_antenna;
-module_param(radio_antenna, int, 0644);
-
-/* ---------------------------------------------------------------------- */
-
-#define MT2032 0x04
-#define MT2030 0x06
-#define MT2040 0x07
-#define MT2050 0x42
-
-static char *microtune_part[] = {
- [ MT2030 ] = "MT2030",
- [ MT2032 ] = "MT2032",
- [ MT2040 ] = "MT2040",
- [ MT2050 ] = "MT2050",
-};
-
-struct microtune_priv {
- struct tuner_i2c_props i2c_props;
-
- unsigned int xogc;
- //unsigned int radio_if2;
-
- u32 frequency;
-};
-
-static int microtune_release(struct dvb_frontend *fe)
-{
- kfree(fe->tuner_priv);
- fe->tuner_priv = NULL;
-
- return 0;
-}
-
-static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- *frequency = priv->frequency;
- return 0;
-}
-
-// IsSpurInBand()?
-static int mt2032_spurcheck(struct dvb_frontend *fe,
- int f1, int f2, int spectrum_from,int spectrum_to)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- int n1=1,n2,f;
-
- f1=f1/1000; //scale to kHz to avoid 32bit overflows
- f2=f2/1000;
- spectrum_from/=1000;
- spectrum_to/=1000;
-
- tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n",
- f1,f2,spectrum_from,spectrum_to);
-
- do {
- n2=-n1;
- f=n1*(f1-f2);
- do {
- n2--;
- f=f-f2;
- tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f);
-
- if( (f>spectrum_from) && (f<spectrum_to))
- tuner_dbg("mt2032 spurcheck triggered: %d\n",n1);
- } while ( (f>(f2-spectrum_to)) || (n2>-5));
- n1++;
- } while (n1<5);
-
- return 1;
-}
-
-static int mt2032_compute_freq(struct dvb_frontend *fe,
- unsigned int rfin,
- unsigned int if1, unsigned int if2,
- unsigned int spectrum_from,
- unsigned int spectrum_to,
- unsigned char *buf,
- int *ret_sel,
- unsigned int xogc) //all in Hz
-{
- struct microtune_priv *priv = fe->tuner_priv;
- unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
- desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
-
- fref= 5250 *1000; //5.25MHz
- desired_lo1=rfin+if1;
-
- lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
- lo1n=lo1/8;
- lo1a=lo1-(lo1n*8);
-
- s=rfin/1000/1000+1090;
-
- if(optimize_vco) {
- if(s>1890) sel=0;
- else if(s>1720) sel=1;
- else if(s>1530) sel=2;
- else if(s>1370) sel=3;
- else sel=4; // >1090
- }
- else {
- if(s>1790) sel=0; // <1958
- else if(s>1617) sel=1;
- else if(s>1449) sel=2;
- else if(s>1291) sel=3;
- else sel=4; // >1090
- }
- *ret_sel=sel;
-
- lo1freq=(lo1a+8*lo1n)*fref;
-
- tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
- rfin,lo1,lo1n,lo1a,sel,lo1freq);
-
- desired_lo2=lo1freq-rfin-if2;
- lo2=(desired_lo2)/fref;
- lo2n=lo2/8;
- lo2a=lo2-(lo2n*8);
- lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
- lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
-
- tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
- rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
-
- if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
- tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
- lo1a, lo1n, lo2a,lo2n);
- return(-1);
- }
-
- mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to);
- // should recalculate lo1 (one step up/down)
-
- // set up MT2032 register map for transfer over i2c
- buf[0]=lo1n-1;
- buf[1]=lo1a | (sel<<4);
- buf[2]=0x86; // LOGC
- buf[3]=0x0f; //reserved
- buf[4]=0x1f;
- buf[5]=(lo2n-1) | (lo2a<<5);
- if(rfin >400*1000*1000)
- buf[6]=0xe4;
- else
- buf[6]=0xf4; // set PKEN per rev 1.2
- buf[7]=8+xogc;
- buf[8]=0xc3; //reserved
- buf[9]=0x4e; //reserved
- buf[10]=0xec; //reserved
- buf[11]=(lo2num&0xff);
- buf[12]=(lo2num>>8) |0x80; // Lo2RST
-
- return 0;
-}
-
-static int mt2032_check_lo_lock(struct dvb_frontend *fe)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- int try,lock=0;
- unsigned char buf[2];
-
- for(try=0;try<10;try++) {
- buf[0]=0x0e;
- tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
- tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
- tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]);
- lock=buf[0] &0x06;
-
- if (lock==6)
- break;
-
- tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
- udelay(1000);
- }
- return lock;
-}
-
-static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- unsigned char buf[2];
- int tad1;
-
- buf[0]=0x0f;
- tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
- tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
- tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]);
- tad1=buf[0]&0x07;
-
- if(tad1 ==0) return lock;
- if(tad1 ==1) return lock;
-
- if(tad1==2) {
- if(sel==0)
- return lock;
- else sel--;
- }
- else {
- if(sel<4)
- sel++;
- else
- return lock;
- }
-
- tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel);
-
- buf[0]=0x0f;
- buf[1]=sel;
- tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
- lock=mt2032_check_lo_lock(fe);
- return lock;
-}
-
-
-static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin,
- unsigned int if1, unsigned int if2,
- unsigned int from, unsigned int to)
-{
- unsigned char buf[21];
- int lint_try,ret,sel,lock=0;
- struct microtune_priv *priv = fe->tuner_priv;
-
- tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
- rfin,if1,if2,from,to);
-
- buf[0]=0;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
- tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
-
- buf[0]=0;
- ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
- if (ret<0)
- return;
-
- // send only the relevant registers per Rev. 1.2
- buf[0]=0;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4);
- buf[5]=5;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4);
- buf[11]=11;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3);
- if(ret!=3)
- tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
-
- // wait for PLLs to lock (per manual), retry LINT if not.
- for(lint_try=0; lint_try<2; lint_try++) {
- lock=mt2032_check_lo_lock(fe);
-
- if(optimize_vco)
- lock=mt2032_optimize_vco(fe,sel,lock);
- if(lock==6) break;
-
- tuner_dbg("mt2032: re-init PLLs by LINT\n");
- buf[0]=7;
- buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
- tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
- mdelay(10);
- buf[1]=8+priv->xogc;
- tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
- }
-
- if (lock!=6)
- tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
-
- buf[0]=2;
- buf[1]=0x20; // LOGC for optimal phase noise
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
- if (ret!=2)
- tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
-}
-
-
-static int mt2032_set_tv_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- int if2,from,to;
-
- // signal bandwidth and picture carrier
- if (params->std & V4L2_STD_525_60) {
- // NTSC
- from = 40750*1000;
- to = 46750*1000;
- if2 = 45750*1000;
- } else {
- // PAL
- from = 32900*1000;
- to = 39900*1000;
- if2 = 38900*1000;
- }
-
- mt2032_set_if_freq(fe, params->frequency*62500,
- 1090*1000*1000, if2, from, to);
-
- return 0;
-}
-
-static int mt2032_set_radio_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- int if2;
-
- if (params->std & V4L2_STD_525_60) {
- tuner_dbg("pinnacle ntsc\n");
- if2 = 41300 * 1000;
- } else {
- tuner_dbg("pinnacle pal\n");
- if2 = 33300 * 1000;
- }
-
- // per Manual for FM tuning: first if center freq. 1085 MHz
- mt2032_set_if_freq(fe, params->frequency * 125 / 2,
- 1085*1000*1000,if2,if2,if2);
-
- return 0;
-}
-
-static int mt2032_set_params(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- int ret = -EINVAL;
-
- switch (params->mode) {
- case V4L2_TUNER_RADIO:
- ret = mt2032_set_radio_freq(fe, params);
- priv->frequency = params->frequency * 125 / 2;
- break;
- case V4L2_TUNER_ANALOG_TV:
- case V4L2_TUNER_DIGITAL_TV:
- ret = mt2032_set_tv_freq(fe, params);
- priv->frequency = params->frequency * 62500;
- break;
- }
-
- return ret;
-}
-
-static struct dvb_tuner_ops mt2032_tuner_ops = {
-#if 0
- .info = {
- .name = "MT2032",
- .frequency_min = ,
- .frequency_max = ,
- .frequency_step = ,
- },
-#endif
- .set_analog_params = mt2032_set_params,
- .release = microtune_release,
- .get_frequency = microtune_get_frequency,
-};
-
-// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
-static int mt2032_init(struct dvb_frontend *fe)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- unsigned char buf[21];
- int ret,xogc,xok=0;
-
- // Initialize Registers per spec.
- buf[1]=2; // Index to register 2
- buf[2]=0xff;
- buf[3]=0x0f;
- buf[4]=0x1f;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4);
-
- buf[5]=6; // Index register 6
- buf[6]=0xe4;
- buf[7]=0x8f;
- buf[8]=0xc3;
- buf[9]=0x4e;
- buf[10]=0xec;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6);
-
- buf[12]=13; // Index register 13
- buf[13]=0x32;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2);
-
- // Adjust XOGC (register 7), wait for XOK
- xogc=7;
- do {
- tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
- mdelay(10);
- buf[0]=0x0e;
- tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
- tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
- xok=buf[0]&0x01;
- tuner_dbg("mt2032: xok = 0x%02x\n",xok);
- if (xok == 1) break;
-
- xogc--;
- tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
- if (xogc == 3) {
- xogc=4; // min. 4 per spec
- break;
- }
- buf[0]=0x07;
- buf[1]=0x88 + xogc;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
- if (ret!=2)
- tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
- } while (xok != 1 );
- priv->xogc=xogc;
-
- memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops));
-
- return(1);
-}
-
-static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- unsigned char buf[2];
- int ret;
-
- buf[0] = 6;
- buf[1] = antenna ? 0x11 : 0x10;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
- tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
-}
-
-static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- unsigned int if1=1218*1000*1000;
- unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
- int ret;
- unsigned char buf[6];
-
- tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n",
- freq,if1,if2);
-
- f_lo1=freq+if1;
- f_lo1=(f_lo1/1000000)*1000000;
-
- f_lo2=f_lo1-freq-if2;
- f_lo2=(f_lo2/50000)*50000;
-
- lo1=f_lo1/4000000;
- lo2=f_lo2/4000000;
-
- f_lo1_modulo= f_lo1-(lo1*4000000);
- f_lo2_modulo= f_lo2-(lo2*4000000);
-
- num1=4*f_lo1_modulo/4000000;
- num2=4096*(f_lo2_modulo/1000)/4000;
-
- // todo spurchecks
-
- div1a=(lo1/12)-1;
- div1b=lo1-(div1a+1)*12;
-
- div2a=(lo2/8)-1;
- div2b=lo2-(div2a+1)*8;
-
- if (debug > 1) {
- tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
- tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
- num1,num2,div1a,div1b,div2a,div2b);
- }
-
- buf[0]=1;
- buf[1]= 4*div1b + num1;
- if(freq<275*1000*1000) buf[1] = buf[1]|0x80;
-
- buf[2]=div1a;
- buf[3]=32*div2b + num2/256;
- buf[4]=num2-(num2/256)*256;
- buf[5]=div2a;
- if(num2!=0) buf[5]=buf[5]|0x40;
-
- if (debug > 1) {
- int i;
- tuner_dbg("bufs is: ");
- for(i=0;i<6;i++)
- printk("%x ",buf[i]);
- printk("\n");
- }
-
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6);
- if (ret!=6)
- tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
-}
-
-static int mt2050_set_tv_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- unsigned int if2;
-
- if (params->std & V4L2_STD_525_60) {
- // NTSC
- if2 = 45750*1000;
- } else {
- // PAL
- if2 = 38900*1000;
- }
- if (V4L2_TUNER_DIGITAL_TV == params->mode) {
- // DVB (pinnacle 300i)
- if2 = 36150*1000;
- }
- mt2050_set_if_freq(fe, params->frequency*62500, if2);
- mt2050_set_antenna(fe, tv_antenna);
-
- return 0;
-}
-
-static int mt2050_set_radio_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- int if2;
-
- if (params->std & V4L2_STD_525_60) {
- tuner_dbg("pinnacle ntsc\n");
- if2 = 41300 * 1000;
- } else {
- tuner_dbg("pinnacle pal\n");
- if2 = 33300 * 1000;
- }
-
- mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2);
- mt2050_set_antenna(fe, radio_antenna);
-
- return 0;
-}
-
-static int mt2050_set_params(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- int ret = -EINVAL;
-
- switch (params->mode) {
- case V4L2_TUNER_RADIO:
- ret = mt2050_set_radio_freq(fe, params);
- priv->frequency = params->frequency * 125 / 2;
- break;
- case V4L2_TUNER_ANALOG_TV:
- case V4L2_TUNER_DIGITAL_TV:
- ret = mt2050_set_tv_freq(fe, params);
- priv->frequency = params->frequency * 62500;
- break;
- }
-
- return ret;
-}
-
-static struct dvb_tuner_ops mt2050_tuner_ops = {
-#if 0
- .info = {
- .name = "MT2050",
- .frequency_min = ,
- .frequency_max = ,
- .frequency_step = ,
- },
-#endif
- .set_analog_params = mt2050_set_params,
- .release = microtune_release,
- .get_frequency = microtune_get_frequency,
-};
-
-static int mt2050_init(struct dvb_frontend *fe)
-{
- struct microtune_priv *priv = fe->tuner_priv;
- unsigned char buf[2];
- int ret;
-
- buf[0]=6;
- buf[1]=0x10;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power
-
- buf[0]=0x0f;
- buf[1]=0x0f;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo
-
- buf[0]=0x0d;
- ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
- tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
-
- tuner_dbg("mt2050: sro is %x\n",buf[0]);
-
- memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops));
-
- return 0;
-}
-
-struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr)
-{
- struct microtune_priv *priv = NULL;
- char *name;
- unsigned char buf[21];
- int company_code;
-
- priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
- fe->tuner_priv = priv;
-
- priv->i2c_props.addr = i2c_addr;
- priv->i2c_props.adap = i2c_adap;
- priv->i2c_props.name = "mt20xx";
-
- //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
-
- memset(buf,0,sizeof(buf));
-
- name = "unknown";
-
- tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
- tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
- if (debug) {
- int i;
- tuner_dbg("MT20xx hexdump:");
- for(i=0;i<21;i++) {
- printk(" %02x",buf[i]);
- if(((i+1)%8)==0) printk(" ");
- }
- printk("\n");
- }
- company_code = buf[0x11] << 8 | buf[0x12];
- tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
- company_code,buf[0x13],buf[0x14]);
-
-#if 0
- /* seems to cause more problems than it solves ... */
- switch (company_code) {
- case 0x30bf:
- case 0x3cbf:
- case 0x3dbf:
- case 0x4d54:
- case 0x8e81:
- case 0x8e91:
- /* ok (?) */
- break;
- default:
- tuner_warn("tuner: microtune: unknown companycode\n");
- return 0;
- }
-#endif
-
- if (buf[0x13] < ARRAY_SIZE(microtune_part) &&
- NULL != microtune_part[buf[0x13]])
- name = microtune_part[buf[0x13]];
- switch (buf[0x13]) {
- case MT2032:
- mt2032_init(fe);
- break;
- case MT2050:
- mt2050_init(fe);
- break;
- default:
- tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
- name);
- return NULL;
- }
-
- strlcpy(fe->ops.tuner_ops.info.name, name,
- sizeof(fe->ops.tuner_ops.info.name));
- tuner_info("microtune %s found, OK\n",name);
- return fe;
-}
-
-EXPORT_SYMBOL_GPL(microtune_attach);
-
-MODULE_DESCRIPTION("Microtune tuner driver");
-MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/linux/drivers/media/video/mt20xx.h b/linux/drivers/media/video/mt20xx.h
deleted file mode 100644
index 5e9c825d2..000000000
--- a/linux/drivers/media/video/mt20xx.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __MT20XX_H__
-#define __MT20XX_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE))
-extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr);
-#else
-static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- return NULL;
-}
-#endif
-
-#endif /* __MT20XX_H__ */
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index 2ea133e8a..ee4349954 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -12,15 +12,12 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/log2.h>
+#include <linux/gpio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-#include <asm/gpio.h>
-#endif
-
/* mt9m001 i2c address 0x5d
* The platform has to define i2c_board_info
* and call i2c_register_board_info() */
@@ -123,7 +120,7 @@ static int mt9m001_init(struct soc_camera_device *icd)
int ret;
/* Disable chip, synchronous option update */
- dev_dbg(icd->vdev->dev, "%s\n", __FUNCTION__);
+ dev_dbg(icd->vdev->dev, "%s\n", __func__);
ret = reg_write(icd, MT9M001_RESET, 1);
if (ret >= 0)
@@ -372,7 +369,7 @@ static int mt9m001_set_register(struct soc_camera_device *icd,
}
#endif
-const struct v4l2_queryctrl mt9m001_controls[] = {
+static const struct v4l2_queryctrl mt9m001_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -620,7 +617,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)
soc_camera_video_stop(&mt9m001->icd);
}
-static int mt9m001_probe(struct i2c_client *client)
+static int mt9m001_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct mt9m001 *mt9m001;
struct soc_camera_device *icd;
@@ -696,12 +694,19 @@ static int mt9m001_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id mt9m001_id[] = {
+ { "mt9m001", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m001_id);
+
static struct i2c_driver mt9m001_i2c_driver = {
.driver = {
.name = "mt9m001",
},
.probe = mt9m001_probe,
.remove = mt9m001_remove,
+ .id_table = mt9m001_id,
};
static int __init mt9m001_mod_init(void)
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index d4b9e2744..1658fe590 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -13,15 +13,12 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/log2.h>
+#include <linux/gpio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
-#ifdef CONFIG_MT9M001_PCA9536_SWITCH
-#include <asm/gpio.h>
-#endif
-
/* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
* The platform has to define i2c_board_info
* and call i2c_register_board_info() */
@@ -91,7 +88,7 @@ static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
struct mt9v022 {
struct i2c_client *client;
struct soc_camera_device icd;
- int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+ int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */
int switch_gpio;
u16 chip_control;
unsigned char datawidth;
@@ -452,7 +449,7 @@ static int mt9v022_set_register(struct soc_camera_device *icd,
}
#endif
-const struct v4l2_queryctrl mt9v022_controls[] = {
+static const struct v4l2_queryctrl mt9v022_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -745,7 +742,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
soc_camera_video_stop(&mt9v022->icd);
}
-static int mt9v022_probe(struct i2c_client *client)
+static int mt9v022_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct mt9v022 *mt9v022;
struct soc_camera_device *icd;
@@ -818,12 +816,19 @@ static int mt9v022_remove(struct i2c_client *client)
return 0;
}
+static const struct i2c_device_id mt9v022_id[] = {
+ { "mt9v022", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+
static struct i2c_driver mt9v022_i2c_driver = {
.driver = {
.name = "mt9v022",
},
.probe = mt9v022_probe,
.remove = mt9v022_remove,
+ .id_table = mt9v022_id,
};
static int __init mt9v022_mod_init(void)
diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c
index 97cc92c82..bf2462a58 100644
--- a/linux/drivers/media/video/mxb.c
+++ b/linux/drivers/media/video/mxb.c
@@ -222,9 +222,8 @@ static int mxb_probe(struct saa7146_dev* dev)
device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
/* check if all devices are present */
- if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c
- || 0 == mxb->tda9840 || 0 == mxb->saa7111a || 0 == mxb->tuner ) {
-
+ if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
+ !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
printk("mxb: did not find all i2c devices. aborting\n");
i2c_del_adapter(&mxb->i2c_adapter);
kfree(mxb);
diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c
index cba851d18..9676c1d6f 100644
--- a/linux/drivers/media/video/ov511.c
+++ b/linux/drivers/media/video/ov511.c
@@ -41,7 +41,6 @@
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
-#include <asm/semaphore.h>
#include <asm/processor.h>
#include <linux/mm.h>
#include <linux/device.h>
@@ -5838,7 +5837,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto error;
memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
- ov->vdev->dev = &dev->dev;
+ ov->vdev->dev = &intf->dev;
video_set_drvdata(ov->vdev, ov);
for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
diff --git a/linux/drivers/media/video/ov511.h b/linux/drivers/media/video/ov511.h
index 2fb0d992c..e797d3c9c 100644
--- a/linux/drivers/media/video/ov511.h
+++ b/linux/drivers/media/video/ov511.h
@@ -18,7 +18,7 @@
#ifdef OV511_DEBUG
#define PDEBUG(level, fmt, args...) \
if (debug >= (level)) info("[%s:%d] " fmt, \
- __FUNCTION__, __LINE__ , ## args)
+ __func__, __LINE__ , ## args)
#else
#define PDEBUG(level, fmt, args...) do {} while(0)
#endif
diff --git a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
index 50c7763d4..9afa4fe47 100644
--- a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -24,11 +24,11 @@ extern int ovcamchip_debug;
#define PDEBUG(level, fmt, args...) \
if (ovcamchip_debug >= (level)) pr_debug("[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+ __func__, __LINE__ , ## args)
#define DDEBUG(level, dev, fmt, args...) \
if (ovcamchip_debug >= (level)) dev_dbg(dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+ __func__, __LINE__ , ## args)
/* Number of times to retry chip detection. Increase this if you are getting
* "Failed to init camera chip" */
diff --git a/linux/drivers/media/video/pvrusb2/Kconfig b/linux/drivers/media/video/pvrusb2/Kconfig
index 6fc1b8be1..4482b2c72 100644
--- a/linux/drivers/media/video/pvrusb2/Kconfig
+++ b/linux/drivers/media/video/pvrusb2/Kconfig
@@ -1,6 +1,8 @@
config VIDEO_PVRUSB2
tristate "Hauppauge WinTV-PVR USB2 support"
- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L2 && I2C
+ depends on VIDEO_MEDIA # Avoids pvrusb = Y / DVB = M
+ depends on HOTPLUG # due to FW_LOADER
select FW_LOADER
select VIDEO_TUNER
select VIDEO_TVEEPROM
@@ -9,6 +11,7 @@ config VIDEO_PVRUSB2
select VIDEO_CX25840
select VIDEO_MSP3400
select VIDEO_WM8775
+ select VIDEO_CS53L32A
---help---
This is a video4linux driver for Conexant 23416 based
usb2 personal video recorder devices.
@@ -16,32 +19,6 @@ config VIDEO_PVRUSB2
To compile this driver as a module, choose M here: the
module will be called pvrusb2
-config VIDEO_PVRUSB2_ONAIR_CREATOR
- bool "pvrusb2 driver support for OnAir Creator model"
- depends on VIDEO_PVRUSB2 && EXPERIMENTAL
- select VIDEO_SAA711X
- select VIDEO_CS53L32A
- ---help---
-
- This option enables support for the OnAir Creator USB tuner
- device. This is a hybrid device, however currently only
- analog mode is supported.
-
- If you are in doubt, say Y.
-
-config VIDEO_PVRUSB2_ONAIR_USB2
- bool "pvrusb2 driver support for OnAir USB2 model"
- depends on VIDEO_PVRUSB2 && EXPERIMENTAL
- select VIDEO_SAA711X
- select VIDEO_CS53L32A
- ---help---
-
- This option enables support for the OnAir USB2 tuner device
- (also known as the Sasem tuner). This is a hybrid device,
- however currently only analog mode is supported.
-
- If you are in doubt, say Y.
-
config VIDEO_PVRUSB2_SYSFS
bool "pvrusb2 sysfs support (EXPERIMENTAL)"
default y
@@ -58,6 +35,25 @@ config VIDEO_PVRUSB2_SYSFS
Note: This feature is experimental and subject to change.
+config VIDEO_PVRUSB2_DVB
+ bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)"
+ default y
+ depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ ---help---
+
+ This option enables a DVB interface for the pvrusb2 driver.
+ If your device does not support digital television, this
+ feature will have no affect on the driver's operation.
+
+ If you are in doubt, say Y.
+
config VIDEO_PVRUSB2_DEBUGIFC
bool "pvrusb2 debug interface"
depends on VIDEO_PVRUSB2_SYSFS
diff --git a/linux/drivers/media/video/pvrusb2/Makefile b/linux/drivers/media/video/pvrusb2/Makefile
index 47284e558..4fda2de69 100644
--- a/linux/drivers/media/video/pvrusb2/Makefile
+++ b/linux/drivers/media/video/pvrusb2/Makefile
@@ -1,5 +1,6 @@
obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
@@ -9,6 +10,12 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
+ $(obj-pvrusb2-dvb-y) \
$(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 3ecf38d40..65babb878 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
@@ -76,7 +75,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != 0) &&
+ ((sp = routing_schemes + sid) != NULL) &&
(hdw->input_val >= 0) &&
(hdw->input_val < sp->cnt)) {
route.input = sp->def[hdw->input_val];
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h
index 536339b68..ac54eed37 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-context.c b/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
index b1b4f3a12..9631ade1e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -1,5 +1,4 @@
/*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -23,107 +22,245 @@
#include "pvrusb2-ioread.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
+#include <linux/wait.h>
#include <linux/kthread.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
-#include <asm/semaphore.h>
#include "compat.h"
+static struct pvr2_context *pvr2_context_exist_first;
+static struct pvr2_context *pvr2_context_exist_last;
+static struct pvr2_context *pvr2_context_notify_first;
+static struct pvr2_context *pvr2_context_notify_last;
+static DEFINE_MUTEX(pvr2_context_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
+static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
+static int pvr2_context_cleanup_flag;
+static int pvr2_context_cleaned_flag;
+static struct task_struct *pvr2_context_thread_ptr;
+
+
+static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
+{
+ int signal_flag = 0;
+ mutex_lock(&pvr2_context_mutex);
+ if (fl) {
+ if (!mp->notify_flag) {
+ signal_flag = (pvr2_context_notify_first == NULL);
+ mp->notify_prev = pvr2_context_notify_last;
+ mp->notify_next = NULL;
+ pvr2_context_notify_last = mp;
+ if (mp->notify_prev) {
+ mp->notify_prev->notify_next = mp;
+ } else {
+ pvr2_context_notify_first = mp;
+ }
+ mp->notify_flag = !0;
+ }
+ } else {
+ if (mp->notify_flag) {
+ mp->notify_flag = 0;
+ if (mp->notify_next) {
+ mp->notify_next->notify_prev = mp->notify_prev;
+ } else {
+ pvr2_context_notify_last = mp->notify_prev;
+ }
+ if (mp->notify_prev) {
+ mp->notify_prev->notify_next = mp->notify_next;
+ } else {
+ pvr2_context_notify_first = mp->notify_next;
+ }
+ }
+ }
+ mutex_unlock(&pvr2_context_mutex);
+ if (signal_flag) wake_up(&pvr2_context_sync_data);
+}
+
static void pvr2_context_destroy(struct pvr2_context *mp)
{
pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
+ pvr2_context_set_notify(mp, 0);
+ mutex_lock(&pvr2_context_mutex);
+ if (mp->exist_next) {
+ mp->exist_next->exist_prev = mp->exist_prev;
+ } else {
+ pvr2_context_exist_last = mp->exist_prev;
+ }
+ if (mp->exist_prev) {
+ mp->exist_prev->exist_next = mp->exist_next;
+ } else {
+ pvr2_context_exist_first = mp->exist_next;
+ }
+ if (!pvr2_context_exist_first) {
+ /* Trigger wakeup on control thread in case it is waiting
+ for an exit condition. */
+ wake_up(&pvr2_context_sync_data);
+ }
+ mutex_unlock(&pvr2_context_mutex);
kfree(mp);
}
static void pvr2_context_notify(struct pvr2_context *mp)
{
- mp->notify_flag = !0;
- wake_up(&mp->wait_data);
+ pvr2_context_set_notify(mp,!0);
}
-static int pvr2_context_thread(void *_mp)
+static void pvr2_context_check(struct pvr2_context *mp)
{
- struct pvr2_channel *ch1,*ch2;
- struct pvr2_context *mp = _mp;
- pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread start)",mp);
-
- /* Finish hardware initialization */
- if (pvr2_hdw_initialize(mp->hdw,
- (void (*)(void *))pvr2_context_notify,mp)) {
- mp->video_stream.stream =
- pvr2_hdw_get_video_stream(mp->hdw);
- /* Trigger interface initialization. By doing this here
- initialization runs in our own safe and cozy thread
- context. */
- if (mp->setup_func) mp->setup_func(mp);
- } else {
+ struct pvr2_channel *ch1, *ch2;
+ pvr2_trace(PVR2_TRACE_CTXT,
+ "pvr2_context %p (notify)", mp);
+ if (!mp->initialized_flag && !mp->disconnect_flag) {
+ mp->initialized_flag = !0;
pvr2_trace(PVR2_TRACE_CTXT,
- "pvr2_context %p (thread skipping setup)",mp);
- /* Even though initialization did not succeed, we're still
- going to enter the wait loop anyway. We need to do this
- in order to await the expected disconnect (which we will
- detect in the normal course of operation). */
- }
-
- /* Now just issue callbacks whenever hardware state changes or if
- there is a disconnect. If there is a disconnect and there are
- no channels left, then there's no reason to stick around anymore
- so we'll self-destruct - tearing down the rest of this driver
- instance along the way. */
- pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread enter loop)",mp);
- while (!mp->disconnect_flag || mp->mc_first) {
- if (mp->notify_flag) {
- mp->notify_flag = 0;
+ "pvr2_context %p (initialize)", mp);
+ /* Finish hardware initialization */
+ if (pvr2_hdw_initialize(mp->hdw,
+ (void (*)(void *))pvr2_context_notify,
+ mp)) {
+ mp->video_stream.stream =
+ pvr2_hdw_get_video_stream(mp->hdw);
+ /* Trigger interface initialization. By doing this
+ here initialization runs in our own safe and
+ cozy thread context. */
+ if (mp->setup_func) mp->setup_func(mp);
+ } else {
pvr2_trace(PVR2_TRACE_CTXT,
- "pvr2_context %p (thread notify)",mp);
- for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
- ch2 = ch1->mc_next;
- if (ch1->check_func) ch1->check_func(ch1);
- }
+ "pvr2_context %p (thread skipping setup)",
+ mp);
+ /* Even though initialization did not succeed,
+ we're still going to continue anyway. We need
+ to do this in order to await the expected
+ disconnect (which we will detect in the normal
+ course of operation). */
}
- wait_event_interruptible(mp->wait_data, mp->notify_flag);
}
- pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread end)",mp);
- pvr2_context_destroy(mp);
+
+ for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
+ ch2 = ch1->mc_next;
+ if (ch1->check_func) ch1->check_func(ch1);
+ }
+
+ if (mp->disconnect_flag && !mp->mc_first) {
+ /* Go away... */
+ pvr2_context_destroy(mp);
+ return;
+ }
+}
+
+
+static int pvr2_context_shutok(void)
+{
+ return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
+}
+
+
+static int pvr2_context_thread_func(void *foo)
+{
+ struct pvr2_context *mp;
+
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
+
+ do {
+ while ((mp = pvr2_context_notify_first) != NULL) {
+ pvr2_context_set_notify(mp, 0);
+ pvr2_context_check(mp);
+ }
+ wait_event_interruptible(
+ pvr2_context_sync_data,
+ ((pvr2_context_notify_first != NULL) ||
+ pvr2_context_shutok()));
+ } while (!pvr2_context_shutok());
+
+ pvr2_context_cleaned_flag = !0;
+ wake_up(&pvr2_context_cleanup_data);
+
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
+
+ wait_event_interruptible(
+ pvr2_context_sync_data,
+ kthread_should_stop());
+
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
+
return 0;
}
+int pvr2_context_global_init(void)
+{
+ pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
+ NULL,
+ "pvrusb2-context");
+ return (pvr2_context_thread_ptr ? 0 : -ENOMEM);
+}
+
+
+void pvr2_context_global_done(void)
+{
+ pvr2_context_cleanup_flag = !0;
+ wake_up(&pvr2_context_sync_data);
+ wait_event_interruptible(
+ pvr2_context_cleanup_data,
+ pvr2_context_cleaned_flag);
+ kthread_stop(pvr2_context_thread_ptr);
+}
+
+
struct pvr2_context *pvr2_context_create(
struct usb_interface *intf,
const struct usb_device_id *devid,
void (*setup_func)(struct pvr2_context *))
{
- struct task_struct *thread;
struct pvr2_context *mp = NULL;
mp = kzalloc(sizeof(*mp),GFP_KERNEL);
if (!mp) goto done;
pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
- init_waitqueue_head(&mp->wait_data);
mp->setup_func = setup_func;
mutex_init(&mp->mutex);
+ mutex_lock(&pvr2_context_mutex);
+ mp->exist_prev = pvr2_context_exist_last;
+ mp->exist_next = NULL;
+ pvr2_context_exist_last = mp;
+ if (mp->exist_prev) {
+ mp->exist_prev->exist_next = mp;
+ } else {
+ pvr2_context_exist_first = mp;
+ }
+ mutex_unlock(&pvr2_context_mutex);
mp->hdw = pvr2_hdw_create(intf,devid);
if (!mp->hdw) {
pvr2_context_destroy(mp);
mp = NULL;
goto done;
}
- thread = kthread_run(pvr2_context_thread, mp, "pvrusb2-context");
- if (!thread) {
- pvr2_context_destroy(mp);
- mp = NULL;
- goto done;
- }
+ pvr2_context_set_notify(mp, !0);
done:
return mp;
}
+static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
+{
+ unsigned int tmsk,mmsk;
+ struct pvr2_channel *cp;
+ struct pvr2_hdw *hdw = mp->hdw;
+ mmsk = pvr2_hdw_get_input_available(hdw);
+ tmsk = mmsk;
+ for (cp = mp->mc_first; cp; cp = cp->mc_next) {
+ if (!cp->input_mask) continue;
+ tmsk &= cp->input_mask;
+ }
+ pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
+ pvr2_hdw_commit_ctl(hdw);
+}
+
+
static void pvr2_context_enter(struct pvr2_context *mp)
{
mutex_lock(&mp->mutex);
@@ -179,7 +316,9 @@ void pvr2_channel_done(struct pvr2_channel *cp)
{
struct pvr2_context *mp = cp->mc_head;
pvr2_context_enter(mp);
+ cp->input_mask = 0;
pvr2_channel_disclaim_stream(cp);
+ pvr2_context_reset_input_limits(mp);
if (cp->mc_next) {
cp->mc_next->mc_prev = cp->mc_prev;
} else {
@@ -195,6 +334,57 @@ void pvr2_channel_done(struct pvr2_channel *cp)
}
+int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
+{
+ unsigned int tmsk,mmsk;
+ int ret = 0;
+ struct pvr2_channel *p2;
+ struct pvr2_hdw *hdw = cp->hdw;
+
+ mmsk = pvr2_hdw_get_input_available(hdw);
+ cmsk &= mmsk;
+ if (cmsk == cp->input_mask) {
+ /* No change; nothing to do */
+ return 0;
+ }
+
+ pvr2_context_enter(cp->mc_head);
+ do {
+ if (!cmsk) {
+ cp->input_mask = 0;
+ pvr2_context_reset_input_limits(cp->mc_head);
+ break;
+ }
+ tmsk = mmsk;
+ for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
+ if (p2 == cp) continue;
+ if (!p2->input_mask) continue;
+ tmsk &= p2->input_mask;
+ }
+ if (!(tmsk & cmsk)) {
+ ret = -EPERM;
+ break;
+ }
+ tmsk &= cmsk;
+ if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
+ /* Internal failure changing allowed list; probably
+ should not happen, but react if it does. */
+ break;
+ }
+ cp->input_mask = cmsk;
+ pvr2_hdw_commit_ctl(hdw);
+ } while (0);
+ pvr2_context_exit(cp->mc_head);
+ return ret;
+}
+
+
+unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
+{
+ return cp->input_mask;
+}
+
+
int pvr2_channel_claim_stream(struct pvr2_channel *cp,
struct pvr2_context_stream *sp)
{
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-context.h b/linux/drivers/media/video/pvrusb2/pvrusb2-context.h
index 1df66ac81..c7cbc28a8 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-context.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-context.h
@@ -1,5 +1,4 @@
/*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -44,6 +43,10 @@ struct pvr2_context_stream {
struct pvr2_context {
struct pvr2_channel *mc_first;
struct pvr2_channel *mc_last;
+ struct pvr2_context *exist_next;
+ struct pvr2_context *exist_prev;
+ struct pvr2_context *notify_next;
+ struct pvr2_context *notify_prev;
struct pvr2_hdw *hdw;
struct pvr2_context_stream video_stream;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
@@ -52,10 +55,9 @@ struct pvr2_context {
struct semaphore mutex;
#endif
int notify_flag;
+ int initialized_flag;
int disconnect_flag;
- wait_queue_head_t wait_data;
-
/* Called after pvr2_context initialization is complete */
void (*setup_func)(struct pvr2_context *);
@@ -67,6 +69,7 @@ struct pvr2_channel {
struct pvr2_channel *mc_prev;
struct pvr2_context_stream *stream;
struct pvr2_hdw *hdw;
+ unsigned int input_mask;
void (*check_func)(struct pvr2_channel *);
};
@@ -77,11 +80,15 @@ void pvr2_context_disconnect(struct pvr2_context *);
void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *);
void pvr2_channel_done(struct pvr2_channel *);
+int pvr2_channel_limit_inputs(struct pvr2_channel *,unsigned int);
+unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *);
int pvr2_channel_claim_stream(struct pvr2_channel *,
struct pvr2_context_stream *);
struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
struct pvr2_context_stream *);
+int pvr2_context_global_init(void);
+void pvr2_context_global_done(void);
#endif /* __PVRUSB2_CONTEXT_H */
/*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 32e43e9d1..5c8942e93 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -68,7 +67,7 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
int ret = 0;
if (!cptr) return -EINVAL;
LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->set_value != 0) {
+ if (cptr->info->set_value) {
if (cptr->info->type == pvr2_ctl_bitmask) {
mask &= cptr->info->def.type_bitmask.valid_bits;
} else if ((cptr->info->type == pvr2_ctl_int)||
@@ -269,7 +268,7 @@ unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
{
if (!cptr) return 0;
- return cptr->info->set_value != 0;
+ return cptr->info->set_value != NULL;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
index c1680053c..0371ae6e6 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index c64bd6078..2f051f797 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
@@ -85,7 +84,9 @@ static const struct routing_scheme_item routing_schemegv[] = {
.vid = CX25840_COMPOSITE2,
.aud = CX25840_AUDIO5,
},
- [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
+ [PVR2_CVAL_INPUT_RADIO] = {
+ /* line-in is used for radio and composite. A GPIO is
+ used to switch between the two choices. */
.vid = CX25840_COMPOSITE1,
.aud = CX25840_AUDIO_SERIAL,
},
@@ -122,7 +123,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
memset(&route,0,sizeof(route));
if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != 0) &&
+ ((sp = routing_schemes + sid) != NULL) &&
(hdw->input_val >= 0) &&
(hdw->input_val < sp->cnt)) {
vid_input = sp->def[hdw->input_val].vid;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
index 54b2844e7..66abf77f5 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h b/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h
index 11537ddf8..be79249f8 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -1,5 +1,4 @@
/*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -54,6 +53,7 @@ extern int pvrusb2_debug;
#define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */
#define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */
#define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */
+#define PVR2_TRACE_DVB_FEED (1 << 28) /* DVB transport feed debug */
#endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index b0687430f..ca892fb78 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -164,6 +163,8 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
int ccnt;
int ret;
u32 gpio_dir,gpio_in,gpio_out;
+ struct pvr2_stream_stats stats;
+ struct pvr2_stream *sp;
ret = pvr2_hdw_is_hsm(hdw);
ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
@@ -182,6 +183,24 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
pvr2_hdw_get_streaming(hdw) ? "on" : "off");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ sp = pvr2_hdw_get_video_stream(hdw);
+ if (sp) {
+ pvr2_stream_get_stats(sp, &stats, 0);
+ ccnt = scnprintf(
+ buf,acnt,
+ "Bytes streamed=%u"
+ " URBs: queued=%u idle=%u ready=%u"
+ " processed=%u failed=%u\n",
+ stats.bytes_processed,
+ stats.buffers_in_queue,
+ stats.buffers_in_idle,
+ stats.buffers_in_ready,
+ stats.buffers_processed,
+ stats.buffers_failed);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ }
+
return bcnt;
}
@@ -220,6 +239,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
return pvr2_hdw_cmd_decoder_reset(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"worker")) {
return pvr2_hdw_untrip(hdw);
+ } else if (debugifc_match_keyword(wptr,wlen,"usbstats")) {
+ pvr2_stream_get_stats(pvr2_hdw_get_video_stream(hdw),
+ NULL, !0);
+ return 0;
}
return -EINVAL;
} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
index 990b02d35..e24ff59f8 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 3434b0e6d..5d036e7e3 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2007 Mike Isely <isely@pobox.com>
*
@@ -32,7 +31,16 @@ pvr2_device_desc structures.
/* This is needed in order to pull in tuner type ids... */
#include <linux/i2c.h>
#include <media/tuner.h>
-
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+#include "pvrusb2-hdw-internal.h"
+#include "lgdt330x.h"
+#include "s5h1409.h"
+#include "s5h1411.h"
+#include "tda10048.h"
+#include "tda18271.h"
+#include "tda8290.h"
+#include "tuner-simple.h"
+#endif
/*------------------------------------------------------------------------*/
@@ -49,7 +57,7 @@ static const char *pvr2_fw1_names_29xxx[] = {
};
static const struct pvr2_device_desc pvr2_device_29xxx = {
- .description = "WinTV PVR USB2 Model Category 29xxxx",
+ .description = "WinTV PVR USB2 Model Category 29xxx",
.shortname = "29xxx",
.client_modules.lst = pvr2_client_29xxx,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
@@ -80,7 +88,7 @@ static const char *pvr2_fw1_names_24xxx[] = {
};
static const struct pvr2_device_desc pvr2_device_24xxx = {
- .description = "WinTV PVR USB2 Model Category 24xxxx",
+ .description = "WinTV PVR USB2 Model Category 24xxx",
.shortname = "24xxx",
.client_modules.lst = pvr2_client_24xxx,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
@@ -116,6 +124,7 @@ static const struct pvr2_device_desc pvr2_device_gotview_2 = {
.flag_has_cx25840 = !0,
.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.flag_has_analogtuner = !0,
+ .flag_has_fmradio = !0,
.flag_has_composite = !0,
.flag_has_svideo = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
@@ -143,10 +152,41 @@ static const struct pvr2_device_desc pvr2_device_gotview_2d = {
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
/*------------------------------------------------------------------------*/
/* OnAir Creator */
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct lgdt330x_config pvr2_lgdt3303_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .clock_polarity_flip = 1,
+};
+
+static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF);
+
+ return 0;
+}
+
+static struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
+ .frontend_attach = pvr2_lgdt3303_attach,
+ .tuner_attach = pvr2_lgh06xf_attach,
+};
+#endif
+
static const char *pvr2_client_onair_creator[] = {
"saa7115",
"tuner",
@@ -162,18 +202,51 @@ static const struct pvr2_device_desc pvr2_device_onair_creator = {
.flag_has_analogtuner = !0,
.flag_has_composite = !0,
.flag_has_svideo = !0,
+ .flag_digital_requires_cx23416 = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
.digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
.default_std_mask = V4L2_STD_NTSC_M,
-};
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_onair_creator_fe_props,
#endif
+};
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
/*------------------------------------------------------------------------*/
/* OnAir USB 2.0 */
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct lgdt330x_config pvr2_lgdt3302_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3302,
+};
+
+static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x61,
+ TUNER_PHILIPS_FCV1236D);
+
+ return 0;
+}
+
+static struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
+ .frontend_attach = pvr2_lgdt3302_attach,
+ .tuner_attach = pvr2_fcv1236d_attach,
+};
+#endif
+
static const char *pvr2_client_onair_usb2[] = {
"saa7115",
"tuner",
@@ -189,17 +262,64 @@ static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
.flag_has_analogtuner = !0,
.flag_has_composite = !0,
.flag_has_svideo = !0,
+ .flag_digital_requires_cx23416 = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
.digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
.default_std_mask = V4L2_STD_NTSC_M,
-};
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_onair_usb2_fe_props,
#endif
+};
/*------------------------------------------------------------------------*/
/* Hauppauge PVR-USB2 Model 73xxx */
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct tda10048_config hauppauge_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_PARALLEL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_50,
+ .inversion = TDA10048_INVERSION_ON,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+ .probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda18271_config hauppauge_tda18271_dvb_config = {
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(tda829x_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, adap->fe, 0x60,
+ &adap->channel.hdw->i2c_adap,
+ &hauppauge_tda18271_dvb_config);
+
+ return 0;
+}
+
+static struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
+ .frontend_attach = pvr2_tda10048_attach,
+ .tuner_attach = pvr2_73xxx_tda18271_8295_attach,
+};
+#endif
+
static const char *pvr2_client_73xxx[] = {
"cx25840",
"tuner",
@@ -210,7 +330,7 @@ static const char *pvr2_fw1_names_73xxx[] = {
};
static const struct pvr2_device_desc pvr2_device_73xxx = {
- .description = "WinTV PVR USB2 Model Category 73xxxx",
+ .description = "WinTV PVR USB2 Model Category 73xxx",
.shortname = "73xxx",
.client_modules.lst = pvr2_client_73xxx,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_73xxx),
@@ -224,6 +344,9 @@ static const struct pvr2_device_desc pvr2_device_73xxx = {
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_73xxx_dvb_props,
+#endif
};
@@ -231,6 +354,80 @@ static const struct pvr2_device_desc pvr2_device_73xxx = {
/*------------------------------------------------------------------------*/
/* Hauppauge PVR-USB2 Model 75xxx */
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct s5h1409_config pvr2_s5h1409_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_PARALLEL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .qam_if = 4000,
+ .inversion = S5H1409_INVERSION_ON,
+ .status_mode = S5H1409_DEMODLOCKING,
+};
+
+static struct s5h1411_config pvr2_s5h1411_config = {
+ .output_mode = S5H1411_PARALLEL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .vsb_if = S5H1411_IF_44000,
+ .qam_if = S5H1411_IF_4000,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3,
+ .if_lvl = 6, .rfagc_top = 0x37, },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+ .if_lvl = 6, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config hauppauge_tda18271_config = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(tda829x_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, adap->fe, 0x60,
+ &adap->channel.hdw->i2c_adap,
+ &hauppauge_tda18271_config);
+
+ return 0;
+}
+
+static struct pvr2_dvb_props pvr2_750xx_dvb_props = {
+ .frontend_attach = pvr2_s5h1409_attach,
+ .tuner_attach = pvr2_tda18271_8295_attach,
+};
+
+static struct pvr2_dvb_props pvr2_751xx_dvb_props = {
+ .frontend_attach = pvr2_s5h1411_attach,
+ .tuner_attach = pvr2_tda18271_8295_attach,
+};
+#endif
+
static const char *pvr2_client_75xxx[] = {
"cx25840",
"tuner",
@@ -240,9 +437,9 @@ static const char *pvr2_fw1_names_75xxx[] = {
"v4l-pvrusb2-73xxx-01.fw",
};
-static const struct pvr2_device_desc pvr2_device_75xxx = {
- .description = "WinTV PVR USB2 Model Category 75xxxx",
- .shortname = "75xxx",
+static const struct pvr2_device_desc pvr2_device_750xx = {
+ .description = "WinTV PVR USB2 Model Category 750xx",
+ .shortname = "750xx",
.client_modules.lst = pvr2_client_75xxx,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
.fx2_firmware.lst = pvr2_fw1_names_75xxx,
@@ -256,6 +453,30 @@ static const struct pvr2_device_desc pvr2_device_75xxx = {
.digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
.default_std_mask = V4L2_STD_NTSC_M,
.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_750xx_dvb_props,
+#endif
+};
+
+static const struct pvr2_device_desc pvr2_device_751xx = {
+ .description = "WinTV PVR USB2 Model Category 751xx",
+ .shortname = "751xx",
+ .client_modules.lst = pvr2_client_75xxx,
+ .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_75xxx,
+ .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
+ .flag_has_cx25840 = !0,
+ .flag_has_hauppauge_rom = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
+ .default_std_mask = V4L2_STD_NTSC_M,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_751xx_dvb_props,
+#endif
};
@@ -271,20 +492,16 @@ struct usb_device_id pvr2_device_table[] = {
.driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
{ USB_DEVICE(0x1164, 0x0602),
.driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d},
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
{ USB_DEVICE(0x11ba, 0x1003),
.driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
-#endif
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
{ USB_DEVICE(0x11ba, 0x1001),
.driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
-#endif
{ USB_DEVICE(0x2040, 0x7300),
.driver_info = (kernel_ulong_t)&pvr2_device_73xxx},
{ USB_DEVICE(0x2040, 0x7500),
- .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
+ .driver_info = (kernel_ulong_t)&pvr2_device_750xx},
{ USB_DEVICE(0x2040, 0x7501),
- .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
+ .driver_info = (kernel_ulong_t)&pvr2_device_751xx},
{ }
};
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index fb5f5d17e..e23ce1d2e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -23,6 +22,9 @@
#include <linux/mod_devicetable.h>
#include <linux/videodev2.h>
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+#include "pvrusb2-dvb.h"
+#endif
/*
@@ -65,6 +67,11 @@ struct pvr2_device_desc {
was initialized from internal ROM. */
struct pvr2_string_table fx2_firmware;
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ /* callback functions to handle attachment of digital tuner & demod */
+ struct pvr2_dvb_props *dvb_props;
+
+#endif
/* Initial standard bits to use for this device, if not zero.
Anything set here is also implied as an available standard.
Note: This is ignored if overridden on the module load line via
@@ -96,21 +103,28 @@ struct pvr2_device_desc {
unsigned char digital_control_scheme;
/* If set, we don't bother trying to load cx23416 firmware. */
- int flag_skip_cx23416_firmware:1;
+ unsigned int flag_skip_cx23416_firmware:1;
+
+ /* If set, the encoder must be healthy in order for digital mode to
+ work (otherwise we assume that digital streaming will work even
+ if we fail to locate firmware for the encoder). If the device
+ doesn't support digital streaming then this flag has no
+ effect. */
+ unsigned int flag_digital_requires_cx23416:1;
/* Device has a hauppauge eeprom which we can interrogate. */
- int flag_has_hauppauge_rom:1;
+ unsigned int flag_has_hauppauge_rom:1;
/* Device does not require a powerup command to be issued. */
- int flag_no_powerup:1;
+ unsigned int flag_no_powerup:1;
/* Device has a cx25840 - this enables special additional logic to
handle it. */
- int flag_has_cx25840:1;
+ unsigned int flag_has_cx25840:1;
/* Device has a wm8775 - this enables special additional logic to
ensure that it is found. */
- int flag_has_wm8775:1;
+ unsigned int flag_has_wm8775:1;
/* Device has IR hardware that can be faked into looking like a
normal Hauppauge i2c IR receiver. This is currently very
@@ -120,15 +134,15 @@ struct pvr2_device_desc {
to virtualize the presence of the non-existant IR receiver chip and
implement the virtual receiver in terms of appropriate FX2
commands. */
- int flag_has_hauppauge_custom_ir:1;
+ unsigned int flag_has_hauppauge_custom_ir:1;
/* These bits define which kinds of sources the device can handle.
Note: Digital tuner presence is inferred by the
digital_control_scheme enumeration. */
- int flag_has_fmradio:1; /* Has FM radio receiver */
- int flag_has_analogtuner:1; /* Has analog tuner */
- int flag_has_composite:1; /* Has composite input */
- int flag_has_svideo:1; /* Has s-video input */
+ unsigned int flag_has_fmradio:1; /* Has FM radio receiver */
+ unsigned int flag_has_analogtuner:1; /* Has analog tuner */
+ unsigned int flag_has_composite:1; /* Has composite input */
+ unsigned int flag_has_svideo:1; /* Has s-video input */
};
extern struct usb_device_id pvr2_device_table[];
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c
new file mode 100644
index 000000000..a317347ad
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c
@@ -0,0 +1,438 @@
+/*
+ * pvrusb2-dvb.c - linux-dvb api interface to the pvrusb2 driver.
+ *
+ * Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kthread.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#include <linux/suspend.h>
+#else
+#include <linux/freezer.h>
+#endif
+#include "compat.h"
+#include "dvbdev.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-io.h"
+#include "pvrusb2-dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap)
+{
+ int ret;
+ unsigned int count;
+ struct pvr2_buffer *bp;
+ struct pvr2_stream *stream;
+
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started");
+ set_freezable();
+
+ stream = adap->channel.stream->stream;
+
+ for (;;) {
+ if (kthread_should_stop()) break;
+
+ /* Not sure about this... */
+ try_to_freeze();
+
+ bp = pvr2_stream_get_ready_buffer(stream);
+ if (bp != NULL) {
+ count = pvr2_buffer_get_count(bp);
+ if (count) {
+ dvb_dmx_swfilter(
+ &adap->demux,
+ adap->buffer_storage[
+ pvr2_buffer_get_id(bp)],
+ count);
+ } else {
+ ret = pvr2_buffer_get_status(bp);
+ if (ret < 0) break;
+ }
+ ret = pvr2_buffer_queue(bp);
+ if (ret < 0) break;
+
+ /* Since we know we did something to a buffer,
+ just go back and try again. No point in
+ blocking unless we really ran out of
+ buffers to process. */
+ continue;
+ }
+
+
+ /* Wait until more buffers become available or we're
+ told not to wait any longer. */
+ ret = wait_event_interruptible(
+ adap->buffer_wait_data,
+ (pvr2_stream_get_ready_count(stream) > 0) ||
+ kthread_should_stop());
+ if (ret < 0) break;
+ }
+
+ /* If we get here and ret is < 0, then an error has occurred.
+ Probably would be a good idea to communicate that to DVB core... */
+
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped");
+
+ return 0;
+}
+
+static int pvr2_dvb_feed_thread(void *data)
+{
+ int stat = pvr2_dvb_feed_func(data);
+ /* from videobuf-dvb.c: */
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }
+ return stat;
+}
+
+static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap)
+{
+ wake_up(&adap->buffer_wait_data);
+}
+
+static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap)
+{
+ unsigned int idx;
+ struct pvr2_stream *stream;
+
+ if (adap->thread) {
+ kthread_stop(adap->thread);
+ adap->thread = NULL;
+ }
+
+ if (adap->channel.stream) {
+ stream = adap->channel.stream->stream;
+ } else {
+ stream = NULL;
+ }
+ if (stream) {
+ pvr2_hdw_set_streaming(adap->channel.hdw, 0);
+ pvr2_stream_set_callback(stream, NULL, NULL);
+ pvr2_stream_kill(stream);
+ pvr2_stream_set_buffer_count(stream, 0);
+ pvr2_channel_claim_stream(&adap->channel, NULL);
+ }
+
+ if (adap->stream_run) {
+ for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+ if (!(adap->buffer_storage[idx])) continue;
+ kfree(adap->buffer_storage[idx]);
+ adap->buffer_storage[idx] = NULL;
+ }
+ adap->stream_run = 0;
+ }
+}
+
+static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap)
+{
+ struct pvr2_context *pvr = adap->channel.mc_head;
+ unsigned int idx;
+ int ret;
+ struct pvr2_buffer *bp;
+ struct pvr2_stream *stream = NULL;
+
+ if (adap->stream_run) return -EIO;
+
+ ret = pvr2_channel_claim_stream(&adap->channel, &pvr->video_stream);
+ /* somebody else already has the stream */
+ if (ret < 0) return ret;
+
+ stream = adap->channel.stream->stream;
+
+ for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+ adap->buffer_storage[idx] = kmalloc(PVR2_DVB_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (!(adap->buffer_storage[idx])) return -ENOMEM;
+ }
+
+ pvr2_stream_set_callback(pvr->video_stream.stream,
+ (pvr2_stream_callback) pvr2_dvb_notify, adap);
+
+ ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT);
+ if (ret < 0) return ret;
+
+ for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+ bp = pvr2_stream_get_buffer(stream, idx);
+ pvr2_buffer_set_buffer(bp,
+ adap->buffer_storage[idx],
+ PVR2_DVB_BUFFER_SIZE);
+ }
+
+ ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1);
+ if (ret < 0) return ret;
+
+ while ((bp = pvr2_stream_get_idle_buffer(stream)) != NULL) {
+ ret = pvr2_buffer_queue(bp);
+ if (ret < 0) return ret;
+ }
+
+ adap->thread = kthread_run(pvr2_dvb_feed_thread, adap, "pvrusb2-dvb");
+
+ if (IS_ERR(adap->thread)) {
+ ret = PTR_ERR(adap->thread);
+ adap->thread = NULL;
+ return ret;
+ }
+
+ adap->stream_run = !0;
+
+ return 0;
+}
+
+static int pvr2_dvb_stream_start(struct pvr2_dvb_adapter *adap)
+{
+ int ret = pvr2_dvb_stream_do_start(adap);
+ if (ret < 0) pvr2_dvb_stream_end(adap);
+ return ret;
+}
+
+static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+ struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv;
+ int ret = 0;
+
+ if (adap == NULL) return -ENODEV;
+
+ mutex_lock(&adap->lock);
+ do {
+ if (onoff) {
+ if (!adap->feedcount) {
+ pvr2_trace(PVR2_TRACE_DVB_FEED,
+ "start feeding demux");
+ ret = pvr2_dvb_stream_start(adap);
+ if (ret < 0) break;
+ }
+ (adap->feedcount)++;
+ } else if (adap->feedcount > 0) {
+ (adap->feedcount)--;
+ if (!adap->feedcount) {
+ pvr2_trace(PVR2_TRACE_DVB_FEED,
+ "stop feeding demux");
+ pvr2_dvb_stream_end(adap);
+ }
+ }
+ } while (0);
+ mutex_unlock(&adap->lock);
+
+ return ret;
+}
+
+static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "start pid: 0x%04x", dvbdmxfeed->pid);
+ return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "stop pid: 0x%04x", dvbdmxfeed->pid);
+ return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0);
+}
+
+static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct pvr2_dvb_adapter *adap = fe->dvb->priv;
+ return pvr2_channel_limit_inputs(
+ &adap->channel,
+ (acquire ? (1 << PVR2_CVAL_INPUT_DTV) : 0));
+}
+
+static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap)
+{
+ int ret;
+
+ ret = dvb_register_adapter(&adap->dvb_adap, "pvrusb2-dvb",
+ THIS_MODULE/*&hdw->usb_dev->owner*/,
+ &adap->channel.hdw->usb_dev->dev,
+ adapter_nr);
+ if (ret < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_register_adapter failed: error %d", ret);
+ goto err;
+ }
+ adap->dvb_adap.priv = adap;
+
+ adap->demux.dmx.capabilities = DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ adap->demux.priv = adap;
+ adap->demux.filternum = 256;
+ adap->demux.feednum = 256;
+ adap->demux.start_feed = pvr2_dvb_start_feed;
+ adap->demux.stop_feed = pvr2_dvb_stop_feed;
+ adap->demux.write_to_decoder = NULL;
+
+ ret = dvb_dmx_init(&adap->demux);
+ if (ret < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_dmx_init failed: error %d", ret);
+ goto err_dmx;
+ }
+
+ adap->dmxdev.filternum = adap->demux.filternum;
+ adap->dmxdev.demux = &adap->demux.dmx;
+ adap->dmxdev.capabilities = 0;
+
+ ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+ if (ret < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_dmxdev_init failed: error %d", ret);
+ goto err_dmx_dev;
+ }
+
+ dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+
+ return 0;
+
+err_dmx_dev:
+ dvb_dmx_release(&adap->demux);
+err_dmx:
+ dvb_unregister_adapter(&adap->dvb_adap);
+err:
+ return ret;
+}
+
+static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap)
+{
+ pvr2_trace(PVR2_TRACE_INFO, "unregistering DVB devices");
+ dvb_net_release(&adap->dvb_net);
+ adap->demux.dmx.close(&adap->demux.dmx);
+ dvb_dmxdev_release(&adap->dmxdev);
+ dvb_dmx_release(&adap->demux);
+ dvb_unregister_adapter(&adap->dvb_adap);
+ return 0;
+}
+
+static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
+{
+ struct pvr2_hdw *hdw = adap->channel.hdw;
+ struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
+ int ret = 0;
+
+ if (dvb_props == NULL) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS, "fe_props not defined!");
+ return -EINVAL;
+ }
+
+ ret = pvr2_channel_limit_inputs(
+ &adap->channel,
+ (1 << PVR2_CVAL_INPUT_DTV));
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "failed to grab control of dtv input (code=%d)",
+ ret);
+ return ret;
+ }
+
+ if (dvb_props->frontend_attach == NULL) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "frontend_attach not defined!");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
+
+ if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "frontend registration failed!");
+ dvb_frontend_detach(adap->fe);
+ adap->fe = NULL;
+ ret = -ENODEV;
+ goto done;
+ }
+
+ if (dvb_props->tuner_attach)
+ dvb_props->tuner_attach(adap);
+
+ if (adap->fe->ops.analog_ops.standby)
+ adap->fe->ops.analog_ops.standby(adap->fe);
+
+ /* Ensure all frontends negotiate bus access */
+ adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
+
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "no frontend was attached!");
+ ret = -ENODEV;
+ return ret;
+ }
+
+ done:
+ pvr2_channel_limit_inputs(&adap->channel, 0);
+ return ret;
+}
+
+static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap)
+{
+ if (adap->fe != NULL) {
+ dvb_unregister_frontend(adap->fe);
+ dvb_frontend_detach(adap->fe);
+ }
+ return 0;
+}
+
+static void pvr2_dvb_destroy(struct pvr2_dvb_adapter *adap)
+{
+ pvr2_dvb_stream_end(adap);
+ pvr2_dvb_frontend_exit(adap);
+ pvr2_dvb_adapter_exit(adap);
+ pvr2_channel_done(&adap->channel);
+ kfree(adap);
+}
+
+static void pvr2_dvb_internal_check(struct pvr2_channel *chp)
+{
+ struct pvr2_dvb_adapter *adap;
+ adap = container_of(chp, struct pvr2_dvb_adapter, channel);
+ if (!adap->channel.mc_head->disconnect_flag) return;
+ pvr2_dvb_destroy(adap);
+}
+
+struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr)
+{
+ int ret = 0;
+ struct pvr2_dvb_adapter *adap;
+ if (!pvr->hdw->hdw_desc->dvb_props) {
+ /* Device lacks a digital interface so don't set up
+ the DVB side of the driver either. For now. */
+ return NULL;
+ }
+ adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+ if (!adap) return adap;
+ pvr2_channel_init(&adap->channel, pvr);
+ adap->channel.check_func = pvr2_dvb_internal_check;
+ init_waitqueue_head(&adap->buffer_wait_data);
+ mutex_init(&adap->lock);
+ ret = pvr2_dvb_adapter_init(adap);
+ if (ret < 0) goto fail1;
+ ret = pvr2_dvb_frontend_init(adap);
+ if (ret < 0) goto fail2;
+ return adap;
+
+fail2:
+ pvr2_dvb_adapter_exit(adap);
+fail1:
+ pvr2_channel_done(&adap->channel);
+ return NULL;
+}
+
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.h
new file mode 100644
index 000000000..c13ecfb13
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.h
@@ -0,0 +1,45 @@
+#ifndef __PVRUSB2_DVB_H__
+#define __PVRUSB2_DVB_H__
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+#include "pvrusb2-context.h"
+
+#define PVR2_DVB_BUFFER_COUNT 32
+#define PVR2_DVB_BUFFER_SIZE PAGE_ALIGN(0x4000)
+
+struct pvr2_dvb_adapter {
+ struct pvr2_channel channel;
+
+ struct dvb_adapter dvb_adap;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dvb_net dvb_net;
+ struct dvb_frontend *fe;
+
+ int feedcount;
+ int max_feed_count;
+
+ struct task_struct *thread;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
+ struct mutex lock;
+#else
+ struct semaphore lock;
+#endif
+
+ unsigned int stream_run:1;
+
+ wait_queue_head_t buffer_wait_data;
+ char *buffer_storage[PVR2_DVB_BUFFER_COUNT];
+};
+
+struct pvr2_dvb_props {
+ int (*frontend_attach) (struct pvr2_dvb_adapter *);
+ int (*tuner_attach) (struct pvr2_dvb_adapter *);
+};
+
+struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr);
+
+#endif /* __PVRUSB2_DVB_H__ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index b831559bd..349618395 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
index 84242975d..cca3216f9 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 70a2bc251..da5b5a7e9 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
@@ -300,11 +299,20 @@ static int pvr2_encoder_cmd(void *ctxt,
ret = -EBUSY;
}
if (ret) {
+ del_timer_sync(&hdw->encoder_run_timer);
hdw->state_encoder_ok = 0;
pvr2_trace(PVR2_TRACE_STBITS,
"State bit %s <-- %s",
"state_encoder_ok",
(hdw->state_encoder_ok ? "true" : "false"));
+ if (hdw->state_encoder_runok) {
+ hdw->state_encoder_runok = 0;
+ pvr2_trace(PVR2_TRACE_STBITS,
+ "State bit %s <-- %s",
+ "state_encoder_runok",
+ (hdw->state_encoder_runok ?
+ "true" : "false"));
+ }
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Giving up on command."
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h
index 54caf2e3c..232fefbcd 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
index a866c9492..b58369e7f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org>
*
@@ -22,41 +21,41 @@
#ifndef _PVRUSB2_FX2_CMD_H_
#define _PVRUSB2_FX2_CMD_H_
-#define FX2CMD_MEM_WRITE_DWORD 0x01
-#define FX2CMD_MEM_READ_DWORD 0x02
+#define FX2CMD_MEM_WRITE_DWORD 0x01u
+#define FX2CMD_MEM_READ_DWORD 0x02u
-#define FX2CMD_MEM_READ_64BYTES 0x28
+#define FX2CMD_MEM_READ_64BYTES 0x28u
-#define FX2CMD_REG_WRITE 0x04
-#define FX2CMD_REG_READ 0x05
-#define FX2CMD_MEMSEL 0x06
+#define FX2CMD_REG_WRITE 0x04u
+#define FX2CMD_REG_READ 0x05u
+#define FX2CMD_MEMSEL 0x06u
-#define FX2CMD_I2C_WRITE 0x08
-#define FX2CMD_I2C_READ 0x09
+#define FX2CMD_I2C_WRITE 0x08u
+#define FX2CMD_I2C_READ 0x09u
-#define FX2CMD_GET_USB_SPEED 0x0b
+#define FX2CMD_GET_USB_SPEED 0x0bu
-#define FX2CMD_STREAMING_ON 0x36
-#define FX2CMD_STREAMING_OFF 0x37
+#define FX2CMD_STREAMING_ON 0x36u
+#define FX2CMD_STREAMING_OFF 0x37u
-#define FX2CMD_FWPOST1 0x52
+#define FX2CMD_FWPOST1 0x52u
-#define FX2CMD_POWER_OFF 0xdc
-#define FX2CMD_POWER_ON 0xde
+#define FX2CMD_POWER_OFF 0xdcu
+#define FX2CMD_POWER_ON 0xdeu
-#define FX2CMD_DEEP_RESET 0xdd
+#define FX2CMD_DEEP_RESET 0xddu
-#define FX2CMD_GET_EEPROM_ADDR 0xeb
-#define FX2CMD_GET_IR_CODE 0xec
+#define FX2CMD_GET_EEPROM_ADDR 0xebu
+#define FX2CMD_GET_IR_CODE 0xecu
-#define FX2CMD_HCW_DEMOD_RESETIN 0xf0
-#define FX2CMD_HCW_DTV_STREAMING_ON 0xf1
-#define FX2CMD_HCW_DTV_STREAMING_OFF 0xf2
+#define FX2CMD_HCW_DEMOD_RESETIN 0xf0u
+#define FX2CMD_HCW_DTV_STREAMING_ON 0xf1u
+#define FX2CMD_HCW_DTV_STREAMING_OFF 0xf2u
-#define FX2CMD_ONAIR_DTV_STREAMING_ON 0xa0
-#define FX2CMD_ONAIR_DTV_STREAMING_OFF 0xa1
-#define FX2CMD_ONAIR_DTV_POWER_ON 0xa2
-#define FX2CMD_ONAIR_DTV_POWER_OFF 0xa3
+#define FX2CMD_ONAIR_DTV_STREAMING_ON 0xa0u
+#define FX2CMD_ONAIR_DTV_STREAMING_OFF 0xa1u
+#define FX2CMD_ONAIR_DTV_POWER_ON 0xa2u
+#define FX2CMD_ONAIR_DTV_POWER_OFF 0xa3u
#endif /* _PVRUSB2_FX2_CMD_H_ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 631973652..f75dd1613 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -254,6 +253,7 @@ struct pvr2_hdw {
int state_encoder_run; /* Encoder is running */
int state_encoder_config; /* Encoder is configured */
int state_encoder_waitok; /* Encoder pre-wait done */
+ int state_encoder_runok; /* Encoder has run for >= .25 sec */
int state_decoder_run; /* Decoder is running */
int state_usbstream_run; /* FX2 is streaming */
int state_decoder_quiescent; /* Decoder idle for > 50msec */
@@ -283,6 +283,9 @@ struct pvr2_hdw {
/* Timer for measuring encoder pre-wait time */
struct timer_list encoder_wait_timer;
+ /* Timer for measuring encoder minimum run time */
+ struct timer_list encoder_run_timer;
+
/* Place to block while waiting for state changes */
wait_queue_head_t state_wait_data;
@@ -348,8 +351,10 @@ struct pvr2_hdw {
int v4l_minor_number_vbi;
int v4l_minor_number_radio;
- /* Bit mask of PVR2_CVAL_INPUT choices which are valid */
+ /* Bit mask of PVR2_CVAL_INPUT choices which are valid for the hardware */
unsigned int input_avail_mask;
+ /* Bit mask of PVR2_CVAL_INPUT choices which are currenly allowed */
+ unsigned int input_allowed_mask;
/* Location of eeprom or a negative number if none */
int eeprom_addr;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 77edc72a2..f78bc351f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -25,7 +24,6 @@
#include <linux/firmware.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-#include <asm/semaphore.h>
#include "pvrusb2.h"
#include "pvrusb2-std.h"
#include "pvrusb2-util.h"
@@ -42,6 +40,23 @@
#define TV_MIN_FREQ 55250000L
#define TV_MAX_FREQ 850000000L
+/* This defines a minimum interval that the decoder must remain quiet
+ before we are allowed to start it running. */
+#define TIME_MSEC_DECODER_WAIT 50
+
+/* This defines a minimum interval that the encoder must remain quiet
+ before we are allowed to configure it. I had this originally set to
+ 50msec, but Martin Dauskardt <martin.dauskardt@gmx.de> reports that
+ things work better when it's set to 100msec. */
+#define TIME_MSEC_ENCODER_WAIT 100
+
+/* This defines the minimum interval that the encoder must successfully run
+ before we consider that the encoder has run at least once since its
+ firmware has been loaded. This measurement is in important for cases
+ where we can't do something until we know that the encoder has been run
+ at least once. */
+#define TIME_MSEC_ENCODER_OK 250
+
static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
static DEFINE_MUTEX(pvr2_unit_mtx);
@@ -69,6 +84,16 @@ MODULE_PARM_DESC(video_std,"specify initial video standard");
module_param_array(tolerance, int, NULL, 0444);
MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
+/* US Broadcast channel 7 (175.25 MHz) */
+static int default_tv_freq = 175250000L;
+/* 104.3 MHz, a usable FM station for my area */
+static int default_radio_freq = 104300000L;
+
+module_param_named(tv_freq, default_tv_freq, int, 0444);
+MODULE_PARM_DESC(tv_freq, "specify initial television frequency");
+module_param_named(radio_freq, default_radio_freq, int, 0444);
+MODULE_PARM_DESC(radio_freq, "specify initial radio frequency");
+
#define PVR2_CTL_WRITE_ENDPOINT 0x01
#define PVR2_CTL_READ_ENDPOINT 0x81
@@ -218,6 +243,40 @@ static const char *pvr2_state_names[] = {
};
+struct pvr2_fx2cmd_descdef {
+ unsigned char id;
+ unsigned char *desc;
+};
+
+static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = {
+ {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"},
+ {FX2CMD_MEM_READ_DWORD, "read encoder dword"},
+ {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"},
+ {FX2CMD_REG_WRITE, "write encoder register"},
+ {FX2CMD_REG_READ, "read encoder register"},
+ {FX2CMD_MEMSEL, "encoder memsel"},
+ {FX2CMD_I2C_WRITE, "i2c write"},
+ {FX2CMD_I2C_READ, "i2c read"},
+ {FX2CMD_GET_USB_SPEED, "get USB speed"},
+ {FX2CMD_STREAMING_ON, "stream on"},
+ {FX2CMD_STREAMING_OFF, "stream off"},
+ {FX2CMD_FWPOST1, "fwpost1"},
+ {FX2CMD_POWER_OFF, "power off"},
+ {FX2CMD_POWER_ON, "power on"},
+ {FX2CMD_DEEP_RESET, "deep reset"},
+ {FX2CMD_GET_EEPROM_ADDR, "get rom addr"},
+ {FX2CMD_GET_IR_CODE, "get IR code"},
+ {FX2CMD_HCW_DEMOD_RESETIN, "hcw demod resetin"},
+ {FX2CMD_HCW_DTV_STREAMING_ON, "hcw dtv stream on"},
+ {FX2CMD_HCW_DTV_STREAMING_OFF, "hcw dtv stream off"},
+ {FX2CMD_ONAIR_DTV_STREAMING_ON, "onair dtv stream on"},
+ {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"},
+ {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"},
+ {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"},
+};
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
static void pvr2_hdw_state_sched(struct pvr2_hdw *);
static int pvr2_hdw_state_eval(struct pvr2_hdw *);
static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
@@ -233,6 +292,8 @@ static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
static void pvr2_hdw_quiescent_timeout(unsigned long);
static void pvr2_hdw_encoder_wait_timeout(unsigned long);
+static void pvr2_hdw_encoder_run_timeout(unsigned long);
+static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32);
static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
unsigned int timeout,int probe_fl,
void *write_data,unsigned int write_len,
@@ -371,30 +432,12 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
{
- return ((1 << v) & cptr->hdw->input_avail_mask) != 0;
+ return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
}
static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
{
- struct pvr2_hdw *hdw = cptr->hdw;
-
- if (hdw->input_val != v) {
- hdw->input_val = v;
- hdw->input_dirty = !0;
- }
-
- /* Handle side effects - if we switch to a mode that needs the RF
- tuner, then select the right frequency choice as well and mark
- it dirty. */
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- hdw->freqSelector = 0;
- hdw->freqDirty = !0;
- } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) ||
- (hdw->input_val == PVR2_CVAL_INPUT_DTV)) {
- hdw->freqSelector = 1;
- hdw->freqDirty = !0;
- }
- return 0;
+ return pvr2_hdw_set_input(cptr->hdw,v);
}
static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
@@ -991,7 +1034,7 @@ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
/* Set the currently tuned frequency and account for all possible
driver-core side effects of this action. */
-void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
+static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
{
if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
if (hdw->freqSelector) {
@@ -1213,6 +1256,14 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
time we configure the encoder, then we'll fully configure it. */
hdw->enc_cur_valid = 0;
+ /* Encoder is about to be reset so note that as far as we're
+ concerned now, the encoder has never been run. */
+ del_timer_sync(&hdw->encoder_run_timer);
+ if (hdw->state_encoder_runok) {
+ hdw->state_encoder_runok = 0;
+ trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
+ }
+
/* First prepare firmware loading */
ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
@@ -1230,19 +1281,14 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
- ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
- hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
- hdw->cmd_buffer[1] = 0;
- ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
+ ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_FWPOST1);
+ ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"firmware2 upload prep failed, ret=%d",ret);
release_firmware(fw_entry);
- return ret;
+ goto done;
}
/* Now send firmware */
@@ -1255,7 +1301,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
" must be a multiple of %zu bytes",
fw_files[fwidx],sizeof(u32));
release_firmware(fw_entry);
- return -1;
+ ret = -EINVAL;
+ goto done;
}
fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
@@ -1263,7 +1310,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
release_firmware(fw_entry);
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"failed to allocate memory for firmware2 upload");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto done;
}
pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
@@ -1294,23 +1342,27 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"firmware2 upload transfer failure");
- return ret;
+ goto done;
}
/* Finish upload */
ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
- hdw->cmd_buffer[1] = 0;
- ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
+ ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"firmware2 upload post-proc failure");
}
+
+ done:
+ if (hdw->hdw_desc->signal_routing_scheme ==
+ PVR2_ROUTING_SCHEME_GOTVIEW) {
+ /* Ensure that GPIO 11 is set to output for GOTVIEW
+ hardware. */
+ pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+ }
return ret;
}
@@ -1382,11 +1434,13 @@ int pvr2_hdw_untrip(struct pvr2_hdw *hdw)
}
+#if 0
const char *pvr2_hdw_get_state_name(unsigned int id)
{
if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL;
return pvr2_state_names[id];
}
+#endif /* 0 */
int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
@@ -1690,10 +1744,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
are, but I set them to something usable in the Chicago area just
to make driver testing a little easier. */
- /* US Broadcast channel 7 (175.25 MHz) */
- hdw->freqValTelevision = 175250000L;
- /* 104.3 MHz, a usable FM station for my area */
- hdw->freqValRadio = 104300000L;
+ hdw->freqValTelevision = default_tv_freq;
+ hdw->freqValRadio = default_radio_freq;
// Do not use pvr2_reset_ctl_endpoints() here. It is not
// thread-safe against the normal pvr2_send_request() mechanism.
@@ -1730,6 +1782,13 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
if (!pvr2_hdw_dev_ok(hdw)) return;
+ if (hdw->hdw_desc->signal_routing_scheme ==
+ PVR2_ROUTING_SCHEME_GOTVIEW) {
+ /* Ensure that GPIO 11 is set to output for GOTVIEW
+ hardware. */
+ pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+ }
+
pvr2_hdw_commit_setup(hdw);
hdw->vid_stream = pvr2_stream_create();
@@ -1831,10 +1890,19 @@ int pvr2_hdw_initialize(struct pvr2_hdw *hdw,
void *callback_data)
{
LOCK_TAKE(hdw->big_lock); do {
+ if (hdw->flag_disconnected) {
+ /* Handle a race here: If we're already
+ disconnected by this point, then give up. If we
+ get past this then we'll remain connected for
+ the duration of initialization since the entire
+ initialization sequence is now protected by the
+ big_lock. */
+ break;
+ }
hdw->state_data = callback_data;
hdw->state_func = callback_func;
+ pvr2_hdw_setup(hdw);
} while (0); LOCK_GIVE(hdw->big_lock);
- pvr2_hdw_setup(hdw);
return hdw->flag_init_ok;
}
@@ -1868,6 +1936,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->encoder_wait_timer.data = (unsigned long)hdw;
hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
+ init_timer(&hdw->encoder_run_timer);
+ hdw->encoder_run_timer.data = (unsigned long)hdw;
+ hdw->encoder_run_timer.function = pvr2_hdw_encoder_run_timeout;
+
hdw->master_state = PVR2_STATE_DEAD;
init_waitqueue_head(&hdw->state_wait_data);
@@ -1885,6 +1957,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE;
if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
hdw->input_avail_mask = m;
+ hdw->input_allowed_mask = hdw->input_avail_mask;
/* If not a hybrid device, pathway_state never changes. So
initialize it here to what it should forever be. */
@@ -2075,6 +2148,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
fail:
if (hdw) {
del_timer_sync(&hdw->quiescent_timer);
+ del_timer_sync(&hdw->encoder_run_timer);
del_timer_sync(&hdw->encoder_wait_timer);
if (hdw->workqueue) {
flush_workqueue(hdw->workqueue);
@@ -2137,6 +2211,7 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
hdw->workqueue = NULL;
}
del_timer_sync(&hdw->quiescent_timer);
+ del_timer_sync(&hdw->encoder_run_timer);
del_timer_sync(&hdw->encoder_wait_timer);
if (hdw->fw_buffer) {
kfree(hdw->fw_buffer);
@@ -2357,7 +2432,7 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
- if (cptr->info->is_dirty == 0) continue;
+ if (!cptr->info->is_dirty) continue;
if (!cptr->info->is_dirty(cptr)) continue;
commit_flag = !0;
@@ -2419,7 +2494,7 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
}
}
- if (hdw->input_dirty &&
+ if (hdw->input_dirty && hdw->state_pathway_ok &&
(((hdw->input_val == PVR2_CVAL_INPUT_DTV) ?
PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) !=
hdw->pathway_state)) {
@@ -2484,6 +2559,20 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
hdw->active_stream_type = hdw->desired_stream_type;
}
+ if (hdw->hdw_desc->signal_routing_scheme ==
+ PVR2_ROUTING_SCHEME_GOTVIEW) {
+ u32 b;
+ /* Handle GOTVIEW audio switching */
+ pvr2_hdw_gpio_get_out(hdw,&b);
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ /* Set GPIO 11 */
+ pvr2_hdw_gpio_chg_out(hdw,(1 << 11),~0);
+ } else {
+ /* Clear GPIO 11 */
+ pvr2_hdw_gpio_chg_out(hdw,(1 << 11),0);
+ }
+ }
+
/* Now execute i2c core update */
pvr2_i2c_core_sync(hdw);
@@ -2706,7 +2795,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
u16 address;
unsigned int pipe;
LOCK_TAKE(hdw->big_lock); do {
- if ((hdw->fw_buffer == 0) == !enable_flag) break;
+ if ((hdw->fw_buffer == NULL) == !enable_flag) break;
if (!enable_flag) {
pvr2_trace(PVR2_TRACE_FIRMWARE,
@@ -2775,7 +2864,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
/* Return true if we're in a mode for retrieval CPU firmware */
int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw)
{
- return hdw->fw_buffer != 0;
+ return hdw->fw_buffer != NULL;
}
@@ -3185,6 +3274,67 @@ int pvr2_send_request(struct pvr2_hdw *hdw,
read_data,read_len);
}
+
+static int pvr2_issue_simple_cmd(struct pvr2_hdw *hdw,u32 cmdcode)
+{
+ int ret;
+ unsigned int cnt = 1;
+ unsigned int args = 0;
+ LOCK_TAKE(hdw->ctl_lock);
+ hdw->cmd_buffer[0] = cmdcode & 0xffu;
+ args = (cmdcode >> 8) & 0xffu;
+ args = (args > 2) ? 2 : args;
+ if (args) {
+ cnt += args;
+ hdw->cmd_buffer[1] = (cmdcode >> 16) & 0xffu;
+ if (args > 1) {
+ hdw->cmd_buffer[2] = (cmdcode >> 24) & 0xffu;
+ }
+ }
+ if (pvrusb2_debug & PVR2_TRACE_INIT) {
+ unsigned int idx;
+ unsigned int ccnt,bcnt;
+ char tbuf[50];
+ cmdcode &= 0xffu;
+ bcnt = 0;
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ "Sending FX2 command 0x%x",cmdcode);
+ bcnt += ccnt;
+ for (idx = 0; idx < ARRAY_SIZE(pvr2_fx2cmd_desc); idx++) {
+ if (pvr2_fx2cmd_desc[idx].id == cmdcode) {
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ " \"%s\"",
+ pvr2_fx2cmd_desc[idx].desc);
+ bcnt += ccnt;
+ break;
+ }
+ }
+ if (args) {
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ " (%u",hdw->cmd_buffer[1]);
+ bcnt += ccnt;
+ if (args > 1) {
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ ",%u",hdw->cmd_buffer[2]);
+ bcnt += ccnt;
+ }
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ ")");
+ bcnt += ccnt;
+ }
+ pvr2_trace(PVR2_TRACE_INIT,"%.*s",bcnt,tbuf);
+ }
+ ret = pvr2_send_request(hdw,hdw->cmd_buffer,cnt,NULL,0);
+ LOCK_GIVE(hdw->ctl_lock);
+ return ret;
+}
+
+
int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
{
int ret;
@@ -3292,40 +3442,19 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
- hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
- status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
+ return pvr2_issue_simple_cmd(hdw,FX2CMD_DEEP_RESET);
}
-static int pvr2_hdw_cmd_power_ctrl(struct pvr2_hdw *hdw, int onoff)
-{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- if (onoff) {
- pvr2_trace(PVR2_TRACE_INIT, "Requesting powerup");
- hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
- } else {
- pvr2_trace(PVR2_TRACE_INIT, "Requesting powerdown");
- hdw->cmd_buffer[0] = FX2CMD_POWER_OFF;
- }
- status = pvr2_send_request(hdw, hdw->cmd_buffer, 1, NULL, 0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
-}
-
int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
{
- return pvr2_hdw_cmd_power_ctrl(hdw, 1);
+ return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_ON);
}
+
int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
{
- return pvr2_hdw_cmd_power_ctrl(hdw, 0);
+ return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_OFF);
}
@@ -3352,55 +3481,29 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
{
- int status;
-
- LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,
- "Issuing fe demod wake command (%s)",
- (onoff ? "on" : "off"));
- hdw->flag_ok = !0;
- hdw->cmd_buffer[0] = FX2CMD_HCW_DEMOD_RESETIN;
- hdw->cmd_buffer[1] = onoff;
- status = pvr2_send_request(hdw, hdw->cmd_buffer, 2, NULL, 0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
-
- return status;
+ hdw->flag_ok = !0;
+ return pvr2_issue_simple_cmd(hdw,
+ FX2CMD_HCW_DEMOD_RESETIN |
+ (1 << 8) |
+ ((onoff ? 1 : 0) << 16));
}
static int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff)
{
- int status;
-
- LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,
- "Issuing fe power command to CPLD (%s)",
- (onoff ? "on" : "off"));
- hdw->flag_ok = !0;
- hdw->cmd_buffer[0] =
- (onoff ? FX2CMD_ONAIR_DTV_POWER_ON :
- FX2CMD_ONAIR_DTV_POWER_OFF);
- status = pvr2_send_request(hdw, hdw->cmd_buffer, 1, NULL, 0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
-
- return status;
+ hdw->flag_ok = !0;
+ return pvr2_issue_simple_cmd(hdw,(onoff ?
+ FX2CMD_ONAIR_DTV_POWER_ON :
+ FX2CMD_ONAIR_DTV_POWER_OFF));
}
static int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw,
int onoff)
{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,
- "Issuing onair digital setup command (%s)",
- (onoff ? "on" : "off"));
- hdw->cmd_buffer[0] =
- (onoff ? FX2CMD_ONAIR_DTV_STREAMING_ON :
- FX2CMD_ONAIR_DTV_STREAMING_OFF);
- status = pvr2_send_request(hdw, hdw->cmd_buffer, 1, NULL, 0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
+ return pvr2_issue_simple_cmd(hdw,(onoff ?
+ FX2CMD_ONAIR_DTV_STREAMING_ON :
+ FX2CMD_ONAIR_DTV_STREAMING_OFF));
}
@@ -3430,9 +3533,7 @@ static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl)
/* Supposedly we should always have the power on whether in
digital or analog mode. But for now do what appears to
work... */
- if (digitalFl) pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,!0);
- pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,digitalFl);
- if (!digitalFl) pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,0);
+ pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,digitalFl);
break;
default: break;
}
@@ -3442,7 +3543,7 @@ static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl)
}
-void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff)
+static void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff)
{
/* change some GPIO data
*
@@ -3490,24 +3591,43 @@ static void pvr2_led_ctrl(struct pvr2_hdw *hdw,int onoff)
/* Stop / start video stream transport */
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
{
- int status,cc;
- if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
- hdw->hdw_desc->digital_control_scheme ==
- PVR2_DIGITAL_SCHEME_HAUPPAUGE) {
- cc = (runFl ?
- FX2CMD_HCW_DTV_STREAMING_ON :
- FX2CMD_HCW_DTV_STREAMING_OFF);
- } else {
- cc = (runFl ?
- FX2CMD_STREAMING_ON :
- FX2CMD_STREAMING_OFF);
+ int ret;
+
+ /* If we're in analog mode, then just issue the usual analog
+ command. */
+ if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+ return pvr2_issue_simple_cmd(hdw,
+ (runFl ?
+ FX2CMD_STREAMING_ON :
+ FX2CMD_STREAMING_OFF));
+ /*Note: Not reached */
}
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = cc;
- status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
+ if (hdw->pathway_state != PVR2_PATHWAY_DIGITAL) {
+ /* Whoops, we don't know what mode we're in... */
+ return -EINVAL;
+ }
+
+ /* To get here we have to be in digital mode. The mechanism here
+ is unfortunately different for different vendors. So we switch
+ on the device's digital scheme attribute in order to figure out
+ what to do. */
+ switch (hdw->hdw_desc->digital_control_scheme) {
+ case PVR2_DIGITAL_SCHEME_HAUPPAUGE:
+ return pvr2_issue_simple_cmd(hdw,
+ (runFl ?
+ FX2CMD_HCW_DTV_STREAMING_ON :
+ FX2CMD_HCW_DTV_STREAMING_OFF));
+ case PVR2_DIGITAL_SCHEME_ONAIR:
+ ret = pvr2_issue_simple_cmd(hdw,
+ (runFl ?
+ FX2CMD_STREAMING_ON :
+ FX2CMD_STREAMING_OFF));
+ if (ret) return ret;
+ return pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,runFl);
+ default:
+ return -EINVAL;
+ }
}
@@ -3538,7 +3658,12 @@ static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
if (hdw->state_encoder_config) return 0;
if (hdw->state_decoder_run) return 0;
if (hdw->state_usbstream_run) return 0;
- if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) return 0;
+ if (hdw->pathway_state == PVR2_PATHWAY_DIGITAL) {
+ if (!hdw->hdw_desc->flag_digital_requires_cx23416) return 0;
+ } else if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) {
+ return 0;
+ }
+
if (pvr2_upload_firmware2(hdw) < 0) {
hdw->flag_tripped = !0;
trace_stbit("flag_tripped",hdw->flag_tripped);
@@ -3598,7 +3723,9 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw)
the encoder. */
if (!hdw->state_encoder_waitok) {
hdw->encoder_wait_timer.expires =
- jiffies + (HZ*50/1000);
+ jiffies +
+ (HZ * TIME_MSEC_ENCODER_WAIT
+ / 1000);
add_timer(&hdw->encoder_wait_timer);
}
}
@@ -3615,23 +3742,116 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw)
}
+/* Return true if the encoder should not be running. */
+static int state_check_disable_encoder_run(struct pvr2_hdw *hdw)
+{
+ if (!hdw->state_encoder_ok) {
+ /* Encoder isn't healthy at the moment, so stop it. */
+ return !0;
+ }
+ if (!hdw->state_pathway_ok) {
+ /* Mode is not understood at the moment (i.e. it wants to
+ change), so encoder must be stopped. */
+ return !0;
+ }
+
+ switch (hdw->pathway_state) {
+ case PVR2_PATHWAY_ANALOG:
+ if (!hdw->state_decoder_run) {
+ /* We're in analog mode and the decoder is not
+ running; thus the encoder should be stopped as
+ well. */
+ return !0;
+ }
+ break;
+ case PVR2_PATHWAY_DIGITAL:
+ if (hdw->state_encoder_runok) {
+ /* This is a funny case. We're in digital mode so
+ really the encoder should be stopped. However
+ if it really is running, only kill it after
+ runok has been set. This gives a chance for the
+ onair quirk to function (encoder must run
+ briefly first, at least once, before onair
+ digital streaming can work). */
+ return !0;
+ }
+ break;
+ default:
+ /* Unknown mode; so encoder should be stopped. */
+ return !0;
+ }
+
+ /* If we get here, we haven't found a reason to stop the
+ encoder. */
+ return 0;
+}
+
+
+/* Return true if the encoder should be running. */
+static int state_check_enable_encoder_run(struct pvr2_hdw *hdw)
+{
+ if (!hdw->state_encoder_ok) {
+ /* Don't run the encoder if it isn't healthy... */
+ return 0;
+ }
+ if (!hdw->state_pathway_ok) {
+ /* Don't run the encoder if we don't (yet) know what mode
+ we need to be in... */
+ return 0;
+ }
+
+ switch (hdw->pathway_state) {
+ case PVR2_PATHWAY_ANALOG:
+ if (hdw->state_decoder_run) {
+ /* In analog mode, if the decoder is running, then
+ run the encoder. */
+ return !0;
+ }
+ break;
+ case PVR2_PATHWAY_DIGITAL:
+ if ((hdw->hdw_desc->digital_control_scheme ==
+ PVR2_DIGITAL_SCHEME_ONAIR) &&
+ !hdw->state_encoder_runok) {
+ /* This is a quirk. OnAir hardware won't stream
+ digital until the encoder has been run at least
+ once, for a minimal period of time (empiricially
+ measured to be 1/4 second). So if we're on
+ OnAir hardware and the encoder has never been
+ run at all, then start the encoder. Normal
+ state machine logic in the driver will
+ automatically handle the remaining bits. */
+ return !0;
+ }
+ break;
+ default:
+ /* For completeness (unknown mode; encoder won't run ever) */
+ break;
+ }
+ /* If we get here, then we haven't found any reason to run the
+ encoder, so don't run it. */
+ return 0;
+}
+
+
/* Evaluate whether or not state_encoder_run can change */
static int state_eval_encoder_run(struct pvr2_hdw *hdw)
{
if (hdw->state_encoder_run) {
+ if (!state_check_disable_encoder_run(hdw)) return 0;
if (hdw->state_encoder_ok) {
- if (hdw->state_decoder_run &&
- hdw->state_pathway_ok) return 0;
+ del_timer_sync(&hdw->encoder_run_timer);
if (pvr2_encoder_stop(hdw) < 0) return !0;
}
hdw->state_encoder_run = 0;
} else {
- if (!hdw->state_encoder_ok) return 0;
- if (!hdw->state_decoder_run) return 0;
- if (!hdw->state_pathway_ok) return 0;
- if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) return 0;
+ if (!state_check_enable_encoder_run(hdw)) return 0;
if (pvr2_encoder_start(hdw) < 0) return !0;
hdw->state_encoder_run = !0;
+ if (!hdw->state_encoder_runok) {
+ hdw->encoder_run_timer.expires =
+ jiffies + (HZ * TIME_MSEC_ENCODER_OK / 1000);
+ add_timer(&hdw->encoder_run_timer);
+ }
}
trace_stbit("state_encoder_run",hdw->state_encoder_run);
return !0;
@@ -3660,6 +3880,19 @@ static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
}
+/* Timeout function for encoder run timer. */
+static void pvr2_hdw_encoder_run_timeout(unsigned long data)
+{
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+ if (!hdw->state_encoder_runok) {
+ hdw->state_encoder_runok = !0;
+ trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
+ hdw->state_stale = !0;
+ queue_work(hdw->workqueue,&hdw->workpoll);
+ }
+}
+
+
/* Evaluate whether or not state_decoder_run can change */
static int state_eval_decoder_run(struct pvr2_hdw *hdw)
{
@@ -3691,7 +3924,9 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
but before we did the pending check. */
if (!hdw->state_decoder_quiescent) {
hdw->quiescent_timer.expires =
- jiffies + (HZ*50/1000);
+ jiffies +
+ (HZ * TIME_MSEC_DECODER_WAIT
+ / 1000);
add_timer(&hdw->quiescent_timer);
}
}
@@ -3723,14 +3958,19 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
{
if (hdw->state_usbstream_run) {
+ int fl = !0;
if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
- if (hdw->state_encoder_ok &&
- hdw->state_encoder_run &&
- hdw->state_pathway_ok) return 0;
- } else {
- if (hdw->state_pipeline_req &&
- !hdw->state_pipeline_pause &&
- hdw->state_pathway_ok) return 0;
+ fl = (hdw->state_encoder_ok &&
+ hdw->state_encoder_run);
+ } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+ (hdw->hdw_desc->flag_digital_requires_cx23416)) {
+ fl = hdw->state_encoder_ok;
+ }
+ if (fl &&
+ hdw->state_pipeline_req &&
+ !hdw->state_pipeline_pause &&
+ hdw->state_pathway_ok) {
+ return 0;
}
pvr2_hdw_cmd_usbstream(hdw,0);
hdw->state_usbstream_run = 0;
@@ -3741,6 +3981,19 @@ static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
if (!hdw->state_encoder_ok ||
!hdw->state_encoder_run) return 0;
+ } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+ (hdw->hdw_desc->flag_digital_requires_cx23416)) {
+ if (!hdw->state_encoder_ok) return 0;
+ if (hdw->state_encoder_run) return 0;
+ if (hdw->hdw_desc->digital_control_scheme ==
+ PVR2_DIGITAL_SCHEME_ONAIR) {
+ /* OnAir digital receivers won't stream
+ unless the analog encoder has run first.
+ Why? I have no idea. But don't even
+ try until we know the analog side is
+ known to have run. */
+ if (!hdw->state_encoder_runok) return 0;
+ }
}
if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
hdw->state_usbstream_run = !0;
@@ -3836,6 +4089,24 @@ static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
}
+static unsigned int print_input_mask(unsigned int msk,
+ char *buf,unsigned int acnt)
+{
+ unsigned int idx,ccnt;
+ unsigned int tcnt = 0;
+ for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) {
+ if (!((1 << idx) & msk)) continue;
+ ccnt = scnprintf(buf+tcnt,
+ acnt-tcnt,
+ "%s%s",
+ (tcnt ? ", " : ""),
+ control_values_input[idx]);
+ tcnt += ccnt;
+ }
+ return tcnt;
+}
+
+
static const char *pvr2_pathway_state_name(int id)
{
switch (id) {
@@ -3884,22 +4155,65 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
(hdw->state_encoder_ok ?
"" : " <encode:init>"),
(hdw->state_encoder_run ?
- " <encode:run>" : " <encode:stop>"),
+ (hdw->state_encoder_runok ?
+ " <encode:run>" :
+ " <encode:firstrun>") :
+ (hdw->state_encoder_runok ?
+ " <encode:stop>" :
+ " <encode:virgin>")),
(hdw->state_encoder_config ?
" <encode:configok>" :
(hdw->state_encoder_waitok ?
- "" : " <encode:wait>")),
+ "" : " <encode:waitok>")),
(hdw->state_usbstream_run ?
" <usb:run>" : " <usb:stop>"),
(hdw->state_pathway_ok ?
" <pathway:ok>" : ""));
- break;
case 3:
return scnprintf(
buf,acnt,
"state: %s",
pvr2_get_state_name(hdw->master_state));
- break;
+ case 4: {
+ unsigned int tcnt = 0;
+ unsigned int ccnt;
+
+ ccnt = scnprintf(buf,
+ acnt,
+ "Hardware supported inputs: ");
+ tcnt += ccnt;
+ tcnt += print_input_mask(hdw->input_avail_mask,
+ buf+tcnt,
+ acnt-tcnt);
+ if (hdw->input_avail_mask != hdw->input_allowed_mask) {
+ ccnt = scnprintf(buf+tcnt,
+ acnt-tcnt,
+ "; allowed inputs: ");
+ tcnt += ccnt;
+ tcnt += print_input_mask(hdw->input_allowed_mask,
+ buf+tcnt,
+ acnt-tcnt);
+ }
+ return tcnt;
+ }
+ case 5: {
+ struct pvr2_stream_stats stats;
+ if (!hdw->vid_stream) break;
+ pvr2_stream_get_stats(hdw->vid_stream,
+ &stats,
+ 0);
+ return scnprintf(
+ buf,acnt,
+ "Bytes streamed=%u"
+ " URBs: queued=%u idle=%u ready=%u"
+ " processed=%u failed=%u",
+ stats.bytes_processed,
+ stats.buffers_in_queue,
+ stats.buffers_in_idle,
+ stats.buffers_in_ready,
+ stats.buffers_processed,
+ stats.buffers_failed);
+ }
default: break;
}
return 0;
@@ -3963,7 +4277,9 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
st = PVR2_STATE_DEAD;
} else if (hdw->fw1_state != FW1_STATE_OK) {
st = PVR2_STATE_COLD;
- } else if (analog_mode && !hdw->state_encoder_ok) {
+ } else if ((analog_mode ||
+ hdw->hdw_desc->flag_digital_requires_cx23416) &&
+ !hdw->state_encoder_ok) {
st = PVR2_STATE_WARM;
} else if (hdw->flag_tripped ||
(analog_mode && hdw->flag_decoder_missed)) {
@@ -4009,6 +4325,7 @@ static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw)
queue_work(hdw->workqueue,&hdw->workpoll);
}
+#if 0
void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
struct pvr2_hdw_debug_info *ptr)
@@ -4050,6 +4367,7 @@ void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
} while(0); LOCK_GIVE(hdw->ctl_lock);
}
+#endif /* 0 */
int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
{
@@ -4116,6 +4434,74 @@ unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw)
}
+unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw)
+{
+ return hdw->input_allowed_mask;
+}
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v)
+{
+ if (hdw->input_val != v) {
+ hdw->input_val = v;
+ hdw->input_dirty = !0;
+ }
+
+ /* Handle side effects - if we switch to a mode that needs the RF
+ tuner, then select the right frequency choice as well and mark
+ it dirty. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ hdw->freqSelector = 0;
+ hdw->freqDirty = !0;
+ } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) ||
+ (hdw->input_val == PVR2_CVAL_INPUT_DTV)) {
+ hdw->freqSelector = 1;
+ hdw->freqDirty = !0;
+ }
+ return 0;
+}
+
+
+int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw,
+ unsigned int change_mask,
+ unsigned int change_val)
+{
+ int ret = 0;
+ unsigned int nv,m,idx;
+ LOCK_TAKE(hdw->big_lock);
+ do {
+ nv = hdw->input_allowed_mask & ~change_mask;
+ nv |= (change_val & change_mask);
+ nv &= hdw->input_avail_mask;
+ if (!nv) {
+ /* No legal modes left; return error instead. */
+ ret = -EPERM;
+ break;
+ }
+ hdw->input_allowed_mask = nv;
+ if ((1 << hdw->input_val) & hdw->input_allowed_mask) {
+ /* Current mode is still in the allowed mask, so
+ we're done. */
+ break;
+ }
+ /* Select and switch to a mode that is still in the allowed
+ mask */
+ if (!hdw->input_allowed_mask) {
+ /* Nothing legal; give up */
+ break;
+ }
+ m = hdw->input_allowed_mask;
+ for (idx = 0; idx < (sizeof(m) << 3); idx++) {
+ if (!((1 << idx) & m)) continue;
+ pvr2_hdw_set_input(hdw,idx);
+ break;
+ }
+ } while (0);
+ LOCK_GIVE(hdw->big_lock);
+ return ret;
+}
+
+
/* Find I2C address of eeprom */
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
{
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index e3e965546..4e60f6262 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -92,9 +91,6 @@ enum pvr2_v4l_type {
/* Translate configuration enum to a string label */
const char *pvr2_config_get_name(enum pvr2_config);
-/* Translate a master state enum to a string label */
-const char *pvr2_hdw_get_state_name(unsigned int);
-
struct pvr2_hdw;
/* Create and return a structure for interacting with the underlying
@@ -158,6 +154,19 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
* will be according to PVR_CVAL_INPUT_xxxx definitions. */
unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *);
+/* Return a bit mask of allowed input selections for this device. Mask bits
+ * will be according to PVR_CVAL_INPUT_xxxx definitions. */
+unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *);
+
+/* Change the set of allowed input selections for this device. Both
+ change_mask and change_valu are mask bits according to
+ PVR_CVAL_INPUT_xxxx definitions. The change_mask parameter indicate
+ which settings are being changed and the change_val parameter indicates
+ whether corresponding settings are being set or cleared. */
+int pvr2_hdw_set_input_allowed(struct pvr2_hdw *,
+ unsigned int change_mask,
+ unsigned int change_val);
+
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index 4b0ded374..25e611b2e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 7ce929be8..d715c80ef 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index c838df616..7fa38683b 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index ddf357d1b..362ec49f5 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
index bd0807b90..6ef7a1c0e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
index 7b3be67f5..bf7bd5906 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -100,6 +99,10 @@ struct pvr2_stream {
/* Tracking state for tolerating errors */
unsigned int fail_count;
unsigned int fail_tolerance;
+
+ unsigned int buffers_processed;
+ unsigned int buffers_failed;
+ unsigned int bytes_processed;
};
struct pvr2_buffer {
@@ -470,6 +473,8 @@ static void buffer_complete(struct urb *urb)
(urb->status == -ENOENT) ||
(urb->status == -ECONNRESET) ||
(urb->status == -ESHUTDOWN)) {
+ (sp->buffers_processed)++;
+ sp->bytes_processed += urb->actual_length;
bp->used_count = urb->actual_length;
if (sp->fail_count) {
pvr2_trace(PVR2_TRACE_TOLERANCE,
@@ -481,11 +486,13 @@ static void buffer_complete(struct urb *urb)
// We can tolerate this error, because we're below the
// threshold...
(sp->fail_count)++;
+ (sp->buffers_failed)++;
pvr2_trace(PVR2_TRACE_TOLERANCE,
"stream %p ignoring error %d"
" - fail count increased to %u",
sp,urb->status,sp->fail_count);
} else {
+ (sp->buffers_failed)++;
bp->status = urb->status;
}
spin_unlock_irqrestore(&sp->list_lock,irq_flags);
@@ -539,6 +546,28 @@ void pvr2_stream_set_callback(struct pvr2_stream *sp,
} while(0); mutex_unlock(&sp->mutex);
}
+void pvr2_stream_get_stats(struct pvr2_stream *sp,
+ struct pvr2_stream_stats *stats,
+ int zero_counts)
+{
+ unsigned long irq_flags;
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ if (stats) {
+ stats->buffers_in_queue = sp->q_count;
+ stats->buffers_in_idle = sp->i_count;
+ stats->buffers_in_ready = sp->r_count;
+ stats->buffers_processed = sp->buffers_processed;
+ stats->buffers_failed = sp->buffers_failed;
+ stats->bytes_processed = sp->bytes_processed;
+ }
+ if (zero_counts) {
+ sp->buffers_processed = 0;
+ sp->buffers_failed = 0;
+ sp->bytes_processed = 0;
+ }
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
/* Query / set the nominal buffer count */
int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
{
@@ -603,7 +632,7 @@ void pvr2_stream_kill(struct pvr2_stream *sp)
struct pvr2_buffer *bp;
mutex_lock(&sp->mutex); do {
pvr2_stream_internal_flush(sp);
- while ((bp = pvr2_stream_get_ready_buffer(sp)) != 0) {
+ while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) {
pvr2_buffer_set_idle(bp);
}
if (sp->buffer_total_count != sp->buffer_target_count) {
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-io.h b/linux/drivers/media/video/pvrusb2/pvrusb2-io.h
index b43e5f4cf..0a4b9a114 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-io.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-io.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -36,6 +35,15 @@ enum pvr2_buffer_state {
struct pvr2_stream;
struct pvr2_buffer;
+struct pvr2_stream_stats {
+ unsigned int buffers_in_queue;
+ unsigned int buffers_in_idle;
+ unsigned int buffers_in_ready;
+ unsigned int buffers_processed;
+ unsigned int buffers_failed;
+ unsigned int bytes_processed;
+};
+
/* Initialize / tear down stream structure */
struct pvr2_stream *pvr2_stream_create(void);
void pvr2_stream_destroy(struct pvr2_stream *);
@@ -45,6 +53,9 @@ void pvr2_stream_setup(struct pvr2_stream *,
void pvr2_stream_set_callback(struct pvr2_stream *,
pvr2_stream_callback func,
void *data);
+void pvr2_stream_get_stats(struct pvr2_stream *,
+ struct pvr2_stream_stats *,
+ int zero_counts);
/* Query / set the nominal buffer count */
int pvr2_stream_get_buffer_count(struct pvr2_stream *);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index aef12fecb..fb3ad639f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -174,7 +173,7 @@ static int pvr2_ioread_start(struct pvr2_ioread *cp)
if (!(cp->stream)) return 0;
pvr2_trace(PVR2_TRACE_START_STOP,
"/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
- while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != 0) {
+ while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) {
stat = pvr2_buffer_queue(bp);
if (stat < 0) {
pvr2_trace(PVR2_TRACE_DATA_FLOW,
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h
index fe397e987..f98dafac7 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
index 59f8d7298..ff85b381c 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
@@ -61,6 +60,10 @@ static void pvr_setup_attach(struct pvr2_context *pvr)
{
/* Create association with v4l layer */
pvr2_v4l2_create(pvr);
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ /* Create association with dvb layer */
+ pvr2_dvb_create(pvr);
+#endif
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_create(pvr,class_ptr);
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
@@ -125,6 +128,12 @@ static int __init pvr_init(void)
pvr2_trace(PVR2_TRACE_INIT,"pvr_init");
+ ret = pvr2_context_global_init();
+ if (ret != 0) {
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_init failure code=%d",ret);
+ return ret;
+ }
+
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
class_ptr = pvr2_sysfs_class_create();
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
@@ -136,6 +145,8 @@ static int __init pvr_init(void)
if (pvrusb2_debug) info("Debug mask is %d (0x%x)",
pvrusb2_debug,pvrusb2_debug);
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete");
+
return ret;
}
@@ -148,6 +159,10 @@ static void __exit pvr_exit(void)
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_class_destroy(class_ptr);
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+ pvr2_context_global_done();
+
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete");
}
module_init(pvr_init);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-std.c b/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
index bd7a8de95..1e91401ba 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-std.h b/linux/drivers/media/video/pvrusb2/pvrusb2-std.h
index 07c399375..a35c53d0b 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-std.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-std.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index f672473dd..f6ace8abe 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
@@ -21,7 +20,6 @@
#include <linux/string.h>
#include <linux/slab.h>
-#include <asm/semaphore.h>
#include "pvrusb2-sysfs.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
@@ -73,6 +71,7 @@ struct pvr2_sysfs_ctl_item {
struct device_attribute attr_val;
struct device_attribute attr_custom;
struct pvr2_ctrl *cptr;
+ int ctl_id;
struct pvr2_sysfs *chptr;
struct pvr2_sysfs_ctl_item *item_next;
struct attribute *attr_gen[7];
@@ -85,38 +84,29 @@ struct pvr2_sysfs_class {
struct class class;
};
-static ssize_t show_name(int id,struct device *class_dev,char *buf)
+static ssize_t show_name(struct device *class_dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct pvr2_ctrl *cptr;
- struct pvr2_sysfs *sfp;
+ struct pvr2_sysfs_ctl_item *cip;
const char *name;
-
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
- if (!sfp) return -EINVAL;
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
- if (!cptr) return -EINVAL;
-
- name = pvr2_ctrl_get_desc(cptr);
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name);
-
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_name);
+ name = pvr2_ctrl_get_desc(cip->cptr);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",
+ cip->chptr, cip->ctl_id, name);
if (!name) return -EINVAL;
-
- return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", name);
}
-static ssize_t show_type(int id,struct device *class_dev,char *buf)
+static ssize_t show_type(struct device *class_dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct pvr2_ctrl *cptr;
- struct pvr2_sysfs *sfp;
+ struct pvr2_sysfs_ctl_item *cip;
const char *name;
enum pvr2_ctl_type tp;
-
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
- if (!sfp) return -EINVAL;
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
- if (!cptr) return -EINVAL;
-
- tp = pvr2_ctrl_get_type(cptr);
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_type);
+ tp = pvr2_ctrl_get_type(cip->cptr);
switch (tp) {
case pvr2_ctl_int: name = "integer"; break;
case pvr2_ctl_enum: name = "enum"; break;
@@ -124,403 +114,178 @@ static ssize_t show_type(int id,struct device *class_dev,char *buf)
case pvr2_ctl_bool: name = "boolean"; break;
default: name = "?"; break;
}
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name);
-
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",
+ cip->chptr, cip->ctl_id, name);
if (!name) return -EINVAL;
-
- return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", name);
}
-static ssize_t show_min(int id,struct device *class_dev,char *buf)
+static ssize_t show_min(struct device *class_dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct pvr2_ctrl *cptr;
- struct pvr2_sysfs *sfp;
+ struct pvr2_sysfs_ctl_item *cip;
long val;
-
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
- if (!sfp) return -EINVAL;
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
- if (!cptr) return -EINVAL;
- val = pvr2_ctrl_get_min(cptr);
-
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val);
-
- return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_min);
+ val = pvr2_ctrl_get_min(cip->cptr);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",
+ cip->chptr, cip->ctl_id, val);
+ return scnprintf(buf, PAGE_SIZE, "%ld\n", val);
}
-static ssize_t show_max(int id,struct device *class_dev,char *buf)
+static ssize_t show_max(struct device *class_dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct pvr2_ctrl *cptr;
- struct pvr2_sysfs *sfp;
+ struct pvr2_sysfs_ctl_item *cip;
long val;
-
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
- if (!sfp) return -EINVAL;
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
- if (!cptr) return -EINVAL;
- val = pvr2_ctrl_get_max(cptr);
-
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val);
-
- return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_max);
+ val = pvr2_ctrl_get_max(cip->cptr);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",
+ cip->chptr, cip->ctl_id, val);
+ return scnprintf(buf, PAGE_SIZE, "%ld\n", val);
}
-static ssize_t show_val_norm(int id,struct device *class_dev,char *buf)
+static ssize_t show_val_norm(struct device *class_dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct pvr2_ctrl *cptr;
- struct pvr2_sysfs *sfp;
- int val,ret;
+ struct pvr2_sysfs_ctl_item *cip;
+ int val;
+ int ret;
unsigned int cnt = 0;
-
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
- if (!sfp) return -EINVAL;
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
- if (!cptr) return -EINVAL;
-
- ret = pvr2_ctrl_get_value(cptr,&val);
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val);
+ ret = pvr2_ctrl_get_value(cip->cptr, &val);
if (ret < 0) return ret;
-
- ret = pvr2_ctrl_value_to_sym(cptr,~0,val,
- buf,PAGE_SIZE-1,&cnt);
-
+ ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val,
+ buf, PAGE_SIZE - 1, &cnt);
pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",
- sfp,id,cnt,buf,val);
+ cip->chptr, cip->ctl_id, cnt, buf, val);
buf[cnt] = '\n';
return cnt+1;
}
-static ssize_t show_val_custom(int id,struct device *class_dev,char *buf)
+static ssize_t show_val_custom(struct device *class_dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct pvr2_ctrl *cptr;
- struct pvr2_sysfs *sfp;
- int val,ret;
+ struct pvr2_sysfs_ctl_item *cip;
+ int val;
+ int ret;
unsigned int cnt = 0;
-
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
- if (!sfp) return -EINVAL;
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
- if (!cptr) return -EINVAL;
-
- ret = pvr2_ctrl_get_value(cptr,&val);
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom);
+ ret = pvr2_ctrl_get_value(cip->cptr, &val);
if (ret < 0) return ret;
-
- ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val,
- buf,PAGE_SIZE-1,&cnt);
-
+ ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, ~0, val,
+ buf, PAGE_SIZE - 1, &cnt);
pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",
- sfp,id,cnt,buf,val);
+ cip->chptr, cip->ctl_id, cnt, buf, val);
buf[cnt] = '\n';
return cnt+1;
}
-static ssize_t show_enum(int id,struct device *class_dev,char *buf)
+static ssize_t show_enum(struct device *class_dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct pvr2_ctrl *cptr;
- struct pvr2_sysfs *sfp;
+ struct pvr2_sysfs_ctl_item *cip;
long val;
- unsigned int bcnt,ccnt,ecnt;
-
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
- if (!sfp) return -EINVAL;
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
- if (!cptr) return -EINVAL;
- ecnt = pvr2_ctrl_get_cnt(cptr);
+ unsigned int bcnt, ccnt, ecnt;
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_enum);
+ ecnt = pvr2_ctrl_get_cnt(cip->cptr);
bcnt = 0;
for (val = 0; val < ecnt; val++) {
- pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+ pvr2_ctrl_get_valname(cip->cptr, val, buf + bcnt,
+ PAGE_SIZE - bcnt, &ccnt);
if (!ccnt) continue;
bcnt += ccnt;
if (bcnt >= PAGE_SIZE) break;
buf[bcnt] = '\n';
bcnt++;
}
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",
+ cip->chptr, cip->ctl_id);
return bcnt;
}
-static ssize_t show_bits(int id,struct device *class_dev,char *buf)
+static ssize_t show_bits(struct device *class_dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct pvr2_ctrl *cptr;
- struct pvr2_sysfs *sfp;
- int valid_bits,msk;
- unsigned int bcnt,ccnt;
-
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
- if (!sfp) return -EINVAL;
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
- if (!cptr) return -EINVAL;
- valid_bits = pvr2_ctrl_get_mask(cptr);
+ struct pvr2_sysfs_ctl_item *cip;
+ int valid_bits, msk;
+ unsigned int bcnt, ccnt;
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_bits);
+ valid_bits = pvr2_ctrl_get_mask(cip->cptr);
bcnt = 0;
for (msk = 1; valid_bits; msk <<= 1) {
if (!(msk & valid_bits)) continue;
valid_bits &= ~msk;
- pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+ pvr2_ctrl_get_valname(cip->cptr, msk, buf + bcnt,
+ PAGE_SIZE - bcnt, &ccnt);
bcnt += ccnt;
if (bcnt >= PAGE_SIZE) break;
buf[bcnt] = '\n';
bcnt++;
}
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",
+ cip->chptr, cip->ctl_id);
return bcnt;
}
-static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
+static int store_val_any(struct pvr2_sysfs_ctl_item *cip, int customfl,
const char *buf,unsigned int count)
{
- struct pvr2_ctrl *cptr;
int ret;
int mask,val;
-
- cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (customfl) {
- ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val);
+ ret = pvr2_ctrl_custom_sym_to_value(cip->cptr, buf, count,
+ &mask, &val);
} else {
- ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val);
+ ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, count,
+ &mask, &val);
}
if (ret < 0) return ret;
- ret = pvr2_ctrl_set_mask_value(cptr,mask,val);
- pvr2_hdw_commit_ctl(sfp->channel.hdw);
+ ret = pvr2_ctrl_set_mask_value(cip->cptr, mask, val);
+ pvr2_hdw_commit_ctl(cip->chptr->channel.hdw);
return ret;
}
-static ssize_t store_val_norm(int id,struct device *class_dev,
- const char *buf,size_t count)
+static ssize_t store_val_norm(struct device *class_dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct pvr2_sysfs *sfp;
+ struct pvr2_sysfs_ctl_item *cip;
int ret;
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val);
pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"",
- sfp,id,(int)count,buf);
- ret = store_val_any(id,0,sfp,buf,count);
+ cip->chptr, cip->ctl_id, (int)count, buf);
+ ret = store_val_any(cip, 0, buf, count);
if (!ret) ret = count;
return ret;
}
-static ssize_t store_val_custom(int id,struct device *class_dev,
- const char *buf,size_t count)
+static ssize_t store_val_custom(struct device *class_dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct pvr2_sysfs *sfp;
+ struct pvr2_sysfs_ctl_item *cip;
int ret;
- sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+ cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom);
pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"",
- sfp,id,(int)count,buf);
- ret = store_val_any(id,1,sfp,buf,count);
+ cip->chptr, cip->ctl_id, (int)count, buf);
+ ret = store_val_any(cip, 1, buf, count);
if (!ret) ret = count;
return ret;
}
-/*
- Mike Isely <isely@pobox.com> 30-April-2005
-
- This next batch of horrible preprocessor hackery is needed because the
- kernel's device_attribute mechanism fails to pass the actual
- attribute through to the show / store functions, which means we have no
- way to package up any attribute-specific parameters, like for example the
- control id. So we work around this brain-damage by encoding the control
- id into the show / store functions themselves and pick the function based
- on the control id we're setting up. These macros try to ease the pain.
- Yuck.
-*/
-
-#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
-struct device_attribute *attr, char *buf) \
-{ return sf_name(ctl_id,class_dev,buf); }
-
-#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
-struct device_attribute *attr, const char *buf, size_t count) \
-{ return sf_name(ctl_id,class_dev,buf,count); }
-
-#define CREATE_BATCH(ctl_id) \
-CREATE_SHOW_INSTANCE(show_name,ctl_id) \
-CREATE_SHOW_INSTANCE(show_type,ctl_id) \
-CREATE_SHOW_INSTANCE(show_min,ctl_id) \
-CREATE_SHOW_INSTANCE(show_max,ctl_id) \
-CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \
-CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \
-CREATE_SHOW_INSTANCE(show_enum,ctl_id) \
-CREATE_SHOW_INSTANCE(show_bits,ctl_id) \
-CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \
-CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \
-
-CREATE_BATCH(0)
-CREATE_BATCH(1)
-CREATE_BATCH(2)
-CREATE_BATCH(3)
-CREATE_BATCH(4)
-CREATE_BATCH(5)
-CREATE_BATCH(6)
-CREATE_BATCH(7)
-CREATE_BATCH(8)
-CREATE_BATCH(9)
-CREATE_BATCH(10)
-CREATE_BATCH(11)
-CREATE_BATCH(12)
-CREATE_BATCH(13)
-CREATE_BATCH(14)
-CREATE_BATCH(15)
-CREATE_BATCH(16)
-CREATE_BATCH(17)
-CREATE_BATCH(18)
-CREATE_BATCH(19)
-CREATE_BATCH(20)
-CREATE_BATCH(21)
-CREATE_BATCH(22)
-CREATE_BATCH(23)
-CREATE_BATCH(24)
-CREATE_BATCH(25)
-CREATE_BATCH(26)
-CREATE_BATCH(27)
-CREATE_BATCH(28)
-CREATE_BATCH(29)
-CREATE_BATCH(30)
-CREATE_BATCH(31)
-CREATE_BATCH(32)
-CREATE_BATCH(33)
-CREATE_BATCH(34)
-CREATE_BATCH(35)
-CREATE_BATCH(36)
-CREATE_BATCH(37)
-CREATE_BATCH(38)
-CREATE_BATCH(39)
-CREATE_BATCH(40)
-CREATE_BATCH(41)
-CREATE_BATCH(42)
-CREATE_BATCH(43)
-CREATE_BATCH(44)
-CREATE_BATCH(45)
-CREATE_BATCH(46)
-CREATE_BATCH(47)
-CREATE_BATCH(48)
-CREATE_BATCH(49)
-CREATE_BATCH(50)
-CREATE_BATCH(51)
-CREATE_BATCH(52)
-CREATE_BATCH(53)
-CREATE_BATCH(54)
-CREATE_BATCH(55)
-CREATE_BATCH(56)
-CREATE_BATCH(57)
-CREATE_BATCH(58)
-CREATE_BATCH(59)
-
-struct pvr2_sysfs_func_set {
- ssize_t (*show_name)(struct device *,
- struct device_attribute *attr, char *);
- ssize_t (*show_type)(struct device *,
- struct device_attribute *attr, char *);
- ssize_t (*show_min)(struct device *,
- struct device_attribute *attr, char *);
- ssize_t (*show_max)(struct device *,
- struct device_attribute *attr, char *);
- ssize_t (*show_enum)(struct device *,
- struct device_attribute *attr, char *);
- ssize_t (*show_bits)(struct device *,
- struct device_attribute *attr, char *);
- ssize_t (*show_val_norm)(struct device *,
- struct device_attribute *attr, char *);
- ssize_t (*store_val_norm)(struct device *,
- struct device_attribute *attr,
- const char *,size_t);
- ssize_t (*show_val_custom)(struct device *,
- struct device_attribute *attr, char *);
- ssize_t (*store_val_custom)(struct device *,
- struct device_attribute *attr,
- const char *,size_t);
-};
-
-#define INIT_BATCH(ctl_id) \
-[ctl_id] = { \
- .show_name = show_name_##ctl_id, \
- .show_type = show_type_##ctl_id, \
- .show_min = show_min_##ctl_id, \
- .show_max = show_max_##ctl_id, \
- .show_enum = show_enum_##ctl_id, \
- .show_bits = show_bits_##ctl_id, \
- .show_val_norm = show_val_norm_##ctl_id, \
- .store_val_norm = store_val_norm_##ctl_id, \
- .show_val_custom = show_val_custom_##ctl_id, \
- .store_val_custom = store_val_custom_##ctl_id, \
-} \
-
-static struct pvr2_sysfs_func_set funcs[] = {
- INIT_BATCH(0),
- INIT_BATCH(1),
- INIT_BATCH(2),
- INIT_BATCH(3),
- INIT_BATCH(4),
- INIT_BATCH(5),
- INIT_BATCH(6),
- INIT_BATCH(7),
- INIT_BATCH(8),
- INIT_BATCH(9),
- INIT_BATCH(10),
- INIT_BATCH(11),
- INIT_BATCH(12),
- INIT_BATCH(13),
- INIT_BATCH(14),
- INIT_BATCH(15),
- INIT_BATCH(16),
- INIT_BATCH(17),
- INIT_BATCH(18),
- INIT_BATCH(19),
- INIT_BATCH(20),
- INIT_BATCH(21),
- INIT_BATCH(22),
- INIT_BATCH(23),
- INIT_BATCH(24),
- INIT_BATCH(25),
- INIT_BATCH(26),
- INIT_BATCH(27),
- INIT_BATCH(28),
- INIT_BATCH(29),
- INIT_BATCH(30),
- INIT_BATCH(31),
- INIT_BATCH(32),
- INIT_BATCH(33),
- INIT_BATCH(34),
- INIT_BATCH(35),
- INIT_BATCH(36),
- INIT_BATCH(37),
- INIT_BATCH(38),
- INIT_BATCH(39),
- INIT_BATCH(40),
- INIT_BATCH(41),
- INIT_BATCH(42),
- INIT_BATCH(43),
- INIT_BATCH(44),
- INIT_BATCH(45),
- INIT_BATCH(46),
- INIT_BATCH(47),
- INIT_BATCH(48),
- INIT_BATCH(49),
- INIT_BATCH(50),
- INIT_BATCH(51),
- INIT_BATCH(52),
- INIT_BATCH(53),
- INIT_BATCH(54),
- INIT_BATCH(55),
- INIT_BATCH(56),
- INIT_BATCH(57),
- INIT_BATCH(58),
- INIT_BATCH(59),
-};
-
-
static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
{
struct pvr2_sysfs_ctl_item *cip;
- struct pvr2_sysfs_func_set *fp;
struct pvr2_ctrl *cptr;
unsigned int cnt,acnt;
int ret;
- if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) {
- return;
- }
-
- fp = funcs + ctl_id;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
if (!cptr) return;
@@ -529,6 +294,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
cip->cptr = cptr;
+ cip->ctl_id = ctl_id;
cip->chptr = sfp;
cip->item_next = NULL;
@@ -541,19 +307,19 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cip->attr_name.attr.name = "name";
cip->attr_name.attr.mode = S_IRUGO;
- cip->attr_name.show = fp->show_name;
+ cip->attr_name.show = show_name;
cip->attr_type.attr.name = "type";
cip->attr_type.attr.mode = S_IRUGO;
- cip->attr_type.show = fp->show_type;
+ cip->attr_type.show = show_type;
cip->attr_min.attr.name = "min_val";
cip->attr_min.attr.mode = S_IRUGO;
- cip->attr_min.show = fp->show_min;
+ cip->attr_min.show = show_min;
cip->attr_max.attr.name = "max_val";
cip->attr_max.attr.mode = S_IRUGO;
- cip->attr_max.show = fp->show_max;
+ cip->attr_max.show = show_max;
cip->attr_val.attr.name = "cur_val";
cip->attr_val.attr.mode = S_IRUGO;
@@ -563,11 +329,11 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cip->attr_enum.attr.name = "enum_val";
cip->attr_enum.attr.mode = S_IRUGO;
- cip->attr_enum.show = fp->show_enum;
+ cip->attr_enum.show = show_enum;
cip->attr_bits.attr.name = "bit_val";
cip->attr_bits.attr.mode = S_IRUGO;
- cip->attr_bits.show = fp->show_bits;
+ cip->attr_bits.show = show_bits;
if (pvr2_ctrl_is_writable(cptr)) {
cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;
@@ -578,12 +344,12 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cip->attr_gen[acnt++] = &cip->attr_name.attr;
cip->attr_gen[acnt++] = &cip->attr_type.attr;
cip->attr_gen[acnt++] = &cip->attr_val.attr;
- cip->attr_val.show = fp->show_val_norm;
- cip->attr_val.store = fp->store_val_norm;
+ cip->attr_val.show = show_val_norm;
+ cip->attr_val.store = store_val_norm;
if (pvr2_ctrl_has_custom_symbols(cptr)) {
cip->attr_gen[acnt++] = &cip->attr_custom.attr;
- cip->attr_custom.show = fp->show_val_custom;
- cip->attr_custom.store = fp->store_val_custom;
+ cip->attr_custom.show = show_val_custom;
+ cip->attr_custom.store = store_val_custom;
}
switch (pvr2_ctrl_get_type(cptr)) {
case pvr2_ctl_enum:
@@ -610,8 +376,9 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
if (ret) {
- printk(KERN_WARNING "%s: sysfs_create_group error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "sysfs_create_group error: %d",
+ ret);
return;
}
cip->created_ok = !0;
@@ -642,15 +409,17 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
sfp->debugifc = dip;
ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
dip->debugcmd_created_ok = !0;
}
ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
dip->debuginfo_created_ok = !0;
}
@@ -861,8 +630,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
class_dev->driver_data = sfp;
ret = device_register(class_dev);
if (ret) {
- printk(KERN_ERR "%s: device_register failed\n",
- __FUNCTION__);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_register failed");
kfree(class_dev);
return;
}
@@ -874,8 +643,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->v4l_minor_number_created_ok = !0;
}
@@ -887,8 +657,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_v4l_radio_minor_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->v4l_radio_minor_number_created_ok = !0;
}
@@ -899,8 +670,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_unit_number.store = NULL;
ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->unit_number_created_ok = !0;
}
@@ -912,8 +684,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_bus_info);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->bus_info_created_ok = !0;
}
@@ -925,8 +698,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_hdw_name);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->hdw_name_created_ok = !0;
}
@@ -938,8 +712,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_hdw_desc);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->hdw_desc_created_ok = !0;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
index ff9373b47..6d875bfe7 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
index c65dbe727..efec78516 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h
index 556f12aa9..ef4afaf37 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-util.h b/linux/drivers/media/video/pvrusb2/pvrusb2-util.h
index e53aee416..92b75544e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-util.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-util.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 38b0ff0f5..55cb4021a 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
@@ -58,7 +57,9 @@ struct pvr2_v4l2_fh {
struct pvr2_v4l2_fh *vprev;
wait_queue_head_t wait_data;
int fw_mode_flag;
- int prev_input_val;
+ /* Map contiguous ordinal value to input id */
+ unsigned char *input_map;
+ unsigned int input_cnt;
};
struct pvr2_v4l2 {
@@ -68,10 +69,6 @@ struct pvr2_v4l2 {
struct v4l2_prio_state prio;
- /* Map contiguous ordinal value to input id */
- unsigned char *input_map;
- unsigned int input_cnt;
-
/* streams - Note that these must be separately, individually,
* allocated pointers. This is because the v4l core is going to
* manage their deletion - separately, individually... */
@@ -271,11 +268,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
memset(&tmp,0,sizeof(tmp));
tmp.index = vi->index;
ret = 0;
- if ((vi->index < 0) || (vi->index >= vp->input_cnt)) {
+ if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
ret = -EINVAL;
break;
}
- val = vp->input_map[vi->index];
+ val = fh->input_map[vi->index];
switch (val) {
case PVR2_CVAL_INPUT_TV:
case PVR2_CVAL_INPUT_DTV:
@@ -323,8 +320,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
val = 0;
ret = pvr2_ctrl_get_value(cptr,&val);
vi->index = 0;
- for (idx = 0; idx < vp->input_cnt; idx++) {
- if (vp->input_map[idx] == val) {
+ for (idx = 0; idx < fh->input_cnt; idx++) {
+ if (fh->input_map[idx] == val) {
vi->index = idx;
break;
}
@@ -335,13 +332,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_INPUT:
{
struct v4l2_input *vi = (struct v4l2_input *)arg;
- if ((vi->index < 0) || (vi->index >= vp->input_cnt)) {
+ if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
ret = -ERANGE;
break;
}
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
- vp->input_map[vi->index]);
+ fh->input_map[vi->index]);
break;
}
@@ -840,10 +837,6 @@ static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
pvr2_v4l2_dev_destroy(vp->dev_radio);
vp->dev_radio = NULL;
}
- if (vp->input_map) {
- kfree(vp->input_map);
- vp->input_map = NULL;
- }
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
pvr2_channel_done(&vp->channel);
@@ -901,20 +894,6 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
v4l2_prio_close(&vp->prio, &fhp->prio);
file->private_data = NULL;
- /* Restore the previous input selection, if it makes sense
- to do so. */
- if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
- struct pvr2_ctrl *cp;
- int pval;
- cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
- pvr2_ctrl_get_value(cp,&pval);
- /* Only restore if we're still selecting the radio */
- if (pval == PVR2_CVAL_INPUT_RADIO) {
- pvr2_ctrl_set_value(cp,fhp->prev_input_val);
- pvr2_hdw_commit_ctl(hdw);
- }
- }
-
if (fhp->vnext) {
fhp->vnext->vprev = fhp->vprev;
} else {
@@ -931,6 +910,10 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
pvr2_channel_done(&fhp->channel);
pvr2_trace(PVR2_TRACE_STRUCT,
"Destroying pvr_v4l2_fh id=%p",fhp);
+ if (fhp->input_map) {
+ kfree(fhp->input_map);
+ fhp->input_map = NULL;
+ }
kfree(fhp);
if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
pvr2_v4l2_destroy_no_lock(vp);
@@ -945,6 +928,9 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
struct pvr2_v4l2_fh *fhp;
struct pvr2_v4l2 *vp;
struct pvr2_hdw *hdw;
+ unsigned int input_mask = 0;
+ unsigned int input_cnt,idx;
+ int ret = 0;
dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
@@ -970,6 +956,50 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+ if (dip->v4l_type == VFL_TYPE_RADIO) {
+ /* Opening device as a radio, legal input selection subset
+ is just the radio. */
+ input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
+ } else {
+ /* Opening the main V4L device, legal input selection
+ subset includes all analog inputs. */
+ input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
+ (1 << PVR2_CVAL_INPUT_TV) |
+ (1 << PVR2_CVAL_INPUT_COMPOSITE) |
+ (1 << PVR2_CVAL_INPUT_SVIDEO));
+ }
+ ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
+ if (ret) {
+ pvr2_channel_done(&fhp->channel);
+ pvr2_trace(PVR2_TRACE_STRUCT,
+ "Destroying pvr_v4l2_fh id=%p (input mask error)",
+ fhp);
+
+ kfree(fhp);
+ return ret;
+ }
+
+ input_mask &= pvr2_hdw_get_input_available(hdw);
+ input_cnt = 0;
+ for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
+ if (input_mask & (1 << idx)) input_cnt++;
+ }
+ fhp->input_cnt = input_cnt;
+ fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
+ if (!fhp->input_map) {
+ pvr2_channel_done(&fhp->channel);
+ pvr2_trace(PVR2_TRACE_STRUCT,
+ "Destroying pvr_v4l2_fh id=%p (input map failure)",
+ fhp);
+ kfree(fhp);
+ return -ENOMEM;
+ }
+ input_cnt = 0;
+ for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
+ if (!(input_mask & (1 << idx))) continue;
+ fhp->input_map[input_cnt++] = idx;
+ }
+
fhp->vnext = NULL;
fhp->vprev = vp->vlast;
if (vp->vlast) {
@@ -980,18 +1010,6 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
vp->vlast = fhp;
fhp->vhead = vp;
- /* Opening the /dev/radioX device implies a mode switch.
- So execute that here. Note that you can get the
- IDENTICAL effect merely by opening the normal video
- device and setting the input appropriately. */
- if (dip->v4l_type == VFL_TYPE_RADIO) {
- struct pvr2_ctrl *cp;
- cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
- pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
- pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
- pvr2_hdw_commit_ctl(hdw);
- }
-
fhp->file = file;
file->private_data = fhp;
v4l2_prio_open(&vp->prio,&fhp->prio);
@@ -1226,8 +1244,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
{
struct pvr2_v4l2 *vp;
- struct pvr2_hdw *hdw;
- unsigned int input_mask,input_cnt,idx;
vp = kzalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
@@ -1236,26 +1252,12 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
vp->channel.check_func = pvr2_v4l2_internal_check;
- hdw = vp->channel.mc_head->hdw;
- input_mask = pvr2_hdw_get_input_available(hdw);
- input_cnt = 0;
- for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
- if (input_mask & (1 << idx)) input_cnt++;
- }
- vp->input_cnt = input_cnt;
- vp->input_map = kzalloc(input_cnt,GFP_KERNEL);
- if (!vp->input_map) goto fail;
- input_cnt = 0;
- for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
- if (!(input_mask & (1 << idx))) continue;
- vp->input_map[input_cnt++] = idx;
- }
-
/* register streams */
vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
if (!vp->dev_video) goto fail;
pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
- if (input_mask & (1 << PVR2_CVAL_INPUT_RADIO)) {
+ if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
+ (1 << PVR2_CVAL_INPUT_RADIO)) {
vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
if (!vp->dev_radio) goto fail;
pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
@@ -1265,7 +1267,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
fail:
pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
pvr2_v4l2_destroy_no_lock(vp);
- return 0;
+ return NULL;
}
/*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
index 9a995e2d2..34c011a7b 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 36ce6dc66..b1ff3803f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
@@ -82,7 +81,7 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
if ((sid < ARRAY_SIZE(routing_schemes)) &&
- ((sp = routing_schemes + sid) != 0) &&
+ ((sp = routing_schemes + sid) != NULL) &&
(hdw->input_val >= 0) &&
(hdw->input_val < sp->cnt)) {
route.input = sp->def[hdw->input_val];
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
index 2b917fda0..4ff5b892b 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
index d578f2491..6cdcbf2fe 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
index 8aaeff4e1..807090961 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2.h b/linux/drivers/media/video/pvrusb2/pvrusb2.h
index 1a9a4baf1..240de9b35 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2.h
@@ -1,6 +1,5 @@
/*
*
- * $Id$
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c
index a54d4ddfa..8236b2b2d 100644
--- a/linux/drivers/media/video/pwc/pwc-if.c
+++ b/linux/drivers/media/video/pwc/pwc-if.c
@@ -489,7 +489,7 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
int i;
unsigned long flags;
- PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+ PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__);
spin_lock_irqsave(&pdev->ptrlock, flags);
pdev->full_frames = NULL;
@@ -511,7 +511,7 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
pdev->fill_image = 0;
spin_unlock_irqrestore(&pdev->ptrlock, flags);
- PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
+ PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__);
}
@@ -929,7 +929,7 @@ static void pwc_iso_stop(struct pwc_device *pdev)
struct urb *urb;
urb = pdev->sbuf[i].urb;
- if (urb != 0) {
+ if (urb) {
PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
usb_kill_urb(urb);
}
@@ -945,7 +945,7 @@ static void pwc_iso_free(struct pwc_device *pdev)
struct urb *urb;
urb = pdev->sbuf[i].urb;
- if (urb != 0) {
+ if (urb) {
PWC_DEBUG_MEMORY("Freeing URB\n");
usb_free_urb(urb);
pdev->sbuf[i].urb = NULL;
@@ -1440,7 +1440,7 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long page, pos = 0;
int index;
- PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
+ PWC_DEBUG_MEMORY(">> %s\n", __func__);
pdev = vdev->priv;
size = vma->vm_end - vma->vm_start;
start = vma->vm_start;
@@ -1784,8 +1784,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
/* Allocate video_device structure */
pdev->vdev = video_device_alloc();
- if (pdev->vdev == 0)
- {
+ if (!pdev->vdev) {
PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
kfree(pdev);
return -ENOMEM;
diff --git a/linux/drivers/media/video/pwc/pwc-v4l.c b/linux/drivers/media/video/pwc/pwc-v4l.c
index 32fbe1ae6..174288987 100644
--- a/linux/drivers/media/video/pwc/pwc-v4l.c
+++ b/linux/drivers/media/video/pwc/pwc-v4l.c
@@ -351,8 +351,10 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
#ifdef CONFIG_USB_PWC_DEBUG
- if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+ if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
v4l_printk_ioctl(cmd);
+ printk("\n");
+ }
#endif
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index bef3c9c79..7cc8e9b19 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -49,6 +49,9 @@
#define CICR1_DW_VAL(x) ((x) & CICR1_DW) /* Data bus width */
#define CICR1_PPL_VAL(x) (((x) << 15) & CICR1_PPL) /* Pixels per line */
+#define CICR1_COLOR_SP_VAL(x) (((x) << 3) & CICR1_COLOR_SP) /* color space */
+#define CICR1_RGB_BPP_VAL(x) (((x) << 7) & CICR1_RGB_BPP) /* bpp for rgb */
+#define CICR1_RGBT_CONV_VAL(x) (((x) << 29) & CICR1_RGBT_CONV) /* rgbt conv */
#define CICR2_BLW_VAL(x) (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */
#define CICR2_ELW_VAL(x) (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */
@@ -70,6 +73,19 @@ static DEFINE_MUTEX(camera_lock);
/*
* Structures
*/
+enum pxa_camera_active_dma {
+ DMA_Y = 0x1,
+ DMA_U = 0x2,
+ DMA_V = 0x4,
+};
+
+/* descriptor needed for the PXA DMA engine */
+struct pxa_cam_dma {
+ dma_addr_t sg_dma;
+ struct pxa_dma_desc *sg_cpu;
+ size_t sg_size;
+ int sglen;
+};
/* buffer for one video frame */
struct pxa_buffer {
@@ -78,16 +94,12 @@ struct pxa_buffer {
const struct soc_camera_data_format *fmt;
- /* our descriptor list needed for the PXA DMA engine */
- dma_addr_t sg_dma;
- struct pxa_dma_desc *sg_cpu;
- size_t sg_size;
+ /* our descriptor lists for Y, U and V channels */
+ struct pxa_cam_dma dmas[3];
+
int inwork;
-};
-struct pxa_framebuffer_queue {
- dma_addr_t sg_last_dma;
- struct pxa_dma_desc *sg_last_cpu;
+ enum pxa_camera_active_dma active_dma;
};
struct pxa_camera_dev {
@@ -100,7 +112,9 @@ struct pxa_camera_dev {
unsigned int irq;
void __iomem *base;
- unsigned int dma_chan_y;
+
+ int channels;
+ unsigned int dma_chans[3];
struct pxacamera_platform_data *pdata;
struct resource *res;
@@ -112,6 +126,7 @@ struct pxa_camera_dev {
spinlock_t lock;
struct pxa_buffer *active;
+ struct pxa_dma_desc *sg_tail[3];
};
static const char *pxa_cam_driver_description = "PXA_Camera";
@@ -125,10 +140,21 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
- *size = icd->width * icd->height * ((icd->current_fmt->depth + 7) >> 3);
+ /* planar capture requires Y, U and V buffers to be page aligned */
+ if (pcdev->channels == 3) {
+ *size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */
+ *size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */
+ *size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */
+ } else {
+ *size = icd->width * icd->height *
+ ((icd->current_fmt->depth + 7) >> 3);
+ }
if (0 == *count)
*count = 32;
@@ -145,10 +171,11 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+ int i;
BUG_ON(in_interrupt());
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
&buf->vb, buf->vb.baddr, buf->vb.bsize);
/* This waits until this buffer is out of danger, i.e., until it is no
@@ -157,14 +184,62 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
videobuf_dma_unmap(vq, dma);
videobuf_dma_free(dma);
- if (buf->sg_cpu)
- dma_free_coherent(pcdev->dev, buf->sg_size, buf->sg_cpu,
- buf->sg_dma);
- buf->sg_cpu = NULL;
+ for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
+ if (buf->dmas[i].sg_cpu)
+ dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size,
+ buf->dmas[i].sg_cpu,
+ buf->dmas[i].sg_dma);
+ buf->dmas[i].sg_cpu = NULL;
+ }
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
+static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
+ struct pxa_buffer *buf,
+ struct videobuf_dmabuf *dma, int channel,
+ int sglen, int sg_start, int cibr,
+ unsigned int size)
+{
+ struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
+ int i;
+
+ if (pxa_dma->sg_cpu)
+ dma_free_coherent(pcdev->dev, pxa_dma->sg_size,
+ pxa_dma->sg_cpu, pxa_dma->sg_dma);
+
+ pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
+ pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size,
+ &pxa_dma->sg_dma, GFP_KERNEL);
+ if (!pxa_dma->sg_cpu)
+ return -ENOMEM;
+
+ pxa_dma->sglen = sglen;
+
+ for (i = 0; i < sglen; i++) {
+ int sg_i = sg_start + i;
+ struct scatterlist *sg = dma->sglist;
+ unsigned int dma_len = sg_dma_len(&sg[sg_i]), xfer_len;
+
+ pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr;
+ pxa_dma->sg_cpu[i].dtadr = sg_dma_address(&sg[sg_i]);
+
+ /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
+ xfer_len = (min(dma_len, size) + 7) & ~7;
+
+ pxa_dma->sg_cpu[i].dcmd =
+ DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len;
+ size -= dma_len;
+ pxa_dma->sg_cpu[i].ddadr =
+ pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
+ }
+
+ pxa_dma->sg_cpu[sglen - 1].ddadr = DDADR_STOP;
+ pxa_dma->sg_cpu[sglen - 1].dcmd |= DCMD_ENDIRQEN;
+
+ return 0;
+}
+
static int pxa_videobuf_prepare(struct videobuf_queue *vq,
struct videobuf_buffer *vb, enum v4l2_field field)
{
@@ -173,9 +248,11 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
- int i, ret;
+ int ret;
+ int sglen_y, sglen_yu = 0, sglen_u = 0, sglen_v = 0;
+ int size_y, size_u = 0, size_v = 0;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
/* Added list head initialization on alloc */
@@ -218,49 +295,64 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
if (ret)
goto fail;
- if (buf->sg_cpu)
- dma_free_coherent(pcdev->dev, buf->sg_size, buf->sg_cpu,
- buf->sg_dma);
+ if (pcdev->channels == 3) {
+ /* FIXME the calculations should be more precise */
+ sglen_y = dma->sglen / 2;
+ sglen_u = sglen_v = dma->sglen / 4 + 1;
+ sglen_yu = sglen_y + sglen_u;
+ size_y = size / 2;
+ size_u = size_v = size / 4;
+ } else {
+ sglen_y = dma->sglen;
+ size_y = size;
+ }
+
+ /* init DMA for Y channel */
+ ret = pxa_init_dma_channel(pcdev, buf, dma, 0, sglen_y,
+ 0, 0x28, size_y);
- buf->sg_size = (dma->sglen + 1) * sizeof(struct pxa_dma_desc);
- buf->sg_cpu = dma_alloc_coherent(pcdev->dev, buf->sg_size,
- &buf->sg_dma, GFP_KERNEL);
- if (!buf->sg_cpu) {
- ret = -ENOMEM;
+ if (ret) {
+ dev_err(pcdev->dev,
+ "DMA initialization for Y/RGB failed\n");
goto fail;
}
- dev_dbg(&icd->dev, "nents=%d size: %d sg=0x%p\n",
- dma->sglen, size, dma->sglist);
- for (i = 0; i < dma->sglen; i++) {
- struct scatterlist *sg = dma->sglist;
- unsigned int dma_len = sg_dma_len(&sg[i]), xfer_len;
-
- /* CIBR0 */
- buf->sg_cpu[i].dsadr = pcdev->res->start + 0x28;
- buf->sg_cpu[i].dtadr = sg_dma_address(&sg[i]);
- /* PXA270 Developer's Manual 27.4.4.1:
- * round up to 8 bytes */
- xfer_len = (min(dma_len, size) + 7) & ~7;
- if (xfer_len & 7)
- dev_err(&icd->dev, "Unaligned buffer: "
- "dma_len %u, size %u\n", dma_len, size);
- buf->sg_cpu[i].dcmd = DCMD_FLOWSRC | DCMD_BURST8 |
- DCMD_INCTRGADDR | xfer_len;
- size -= dma_len;
- buf->sg_cpu[i].ddadr = buf->sg_dma + (i + 1) *
- sizeof(struct pxa_dma_desc);
+ if (pcdev->channels == 3) {
+ /* init DMA for U channel */
+ ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u,
+ sglen_y, 0x30, size_u);
+ if (ret) {
+ dev_err(pcdev->dev,
+ "DMA initialization for U failed\n");
+ goto fail_u;
+ }
+
+ /* init DMA for V channel */
+ ret = pxa_init_dma_channel(pcdev, buf, dma, 2, sglen_v,
+ sglen_yu, 0x38, size_v);
+ if (ret) {
+ dev_err(pcdev->dev,
+ "DMA initialization for V failed\n");
+ goto fail_v;
+ }
}
- buf->sg_cpu[dma->sglen - 1].ddadr = DDADR_STOP;
- buf->sg_cpu[dma->sglen - 1].dcmd |= DCMD_ENDIRQEN;
vb->state = VIDEOBUF_PREPARED;
}
buf->inwork = 0;
+ buf->active_dma = DMA_Y;
+ if (pcdev->channels == 3)
+ buf->active_dma |= DMA_U | DMA_V;
return 0;
+fail_v:
+ dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size,
+ buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
+fail_u:
+ dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size,
+ buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
fail:
free_buffer(vq, buf);
out:
@@ -277,11 +369,10 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
struct pxa_camera_dev *pcdev = ici->priv;
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
struct pxa_buffer *active;
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
- int nents = dma->sglen;
unsigned long flags;
+ int i;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
spin_lock_irqsave(&pcdev->lock, flags);
@@ -292,59 +383,63 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
if (!active) {
CIFR |= CIFR_RESET_F;
- DDADR(pcdev->dma_chan_y) = buf->sg_dma;
- DCSR(pcdev->dma_chan_y) = DCSR_RUN;
+
+ for (i = 0; i < pcdev->channels; i++) {
+ DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma;
+ DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+ pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen - 1;
+ }
+
pcdev->active = buf;
CICR0 |= CICR0_ENB;
} else {
- struct videobuf_dmabuf *active_dma =
- videobuf_to_dma(&active->vb);
- /* Stop DMA engine */
- DCSR(pcdev->dma_chan_y) = 0;
-
- /* Add the descriptors we just initialized to the currently
- * running chain
- */
- active->sg_cpu[active_dma->sglen - 1].ddadr = buf->sg_dma;
-
- /* Setup a dummy descriptor with the DMA engines current
- * state
- */
- /* CIBR0 */
- buf->sg_cpu[nents].dsadr = pcdev->res->start + 0x28;
- buf->sg_cpu[nents].dtadr = DTADR(pcdev->dma_chan_y);
- buf->sg_cpu[nents].dcmd = DCMD(pcdev->dma_chan_y);
-
- if (DDADR(pcdev->dma_chan_y) == DDADR_STOP) {
- /* The DMA engine is on the last descriptor, set the
- * next descriptors address to the descriptors
- * we just initialized
- */
- buf->sg_cpu[nents].ddadr = buf->sg_dma;
- } else {
- buf->sg_cpu[nents].ddadr = DDADR(pcdev->dma_chan_y);
- }
+ struct pxa_cam_dma *buf_dma;
+ struct pxa_cam_dma *act_dma;
+ int nents;
- /* The next descriptor is the dummy descriptor */
- DDADR(pcdev->dma_chan_y) = buf->sg_dma + nents *
- sizeof(struct pxa_dma_desc);
+ for (i = 0; i < pcdev->channels; i++) {
+ buf_dma = &buf->dmas[i];
+ act_dma = &active->dmas[i];
+ nents = buf_dma->sglen;
-#ifdef DEBUG
- if (CISR & CISR_IFO_0) {
- dev_warn(pcdev->dev, "FIFO overrun\n");
- DDADR(pcdev->dma_chan_y) = pcdev->active->sg_dma;
-
- CICR0 &= ~CICR0_ENB;
- CIFR |= CIFR_RESET_F;
- DCSR(pcdev->dma_chan_y) = DCSR_RUN;
- CICR0 |= CICR0_ENB;
- } else
-#endif
- DCSR(pcdev->dma_chan_y) = DCSR_RUN;
+ /* Stop DMA engine */
+ DCSR(pcdev->dma_chans[i]) = 0;
+
+ /* Add the descriptors we just initialized to
+ the currently running chain */
+ pcdev->sg_tail[i]->ddadr = buf_dma->sg_dma;
+ pcdev->sg_tail[i] = buf_dma->sg_cpu + buf_dma->sglen - 1;
+
+ /* Setup a dummy descriptor with the DMA engines current
+ * state
+ */
+ buf_dma->sg_cpu[nents].dsadr =
+ pcdev->res->start + 0x28 + i*8; /* CIBRx */
+ buf_dma->sg_cpu[nents].dtadr =
+ DTADR(pcdev->dma_chans[i]);
+ buf_dma->sg_cpu[nents].dcmd =
+ DCMD(pcdev->dma_chans[i]);
+
+ if (DDADR(pcdev->dma_chans[i]) == DDADR_STOP) {
+ /* The DMA engine is on the last
+ descriptor, set the next descriptors
+ address to the descriptors we just
+ initialized */
+ buf_dma->sg_cpu[nents].ddadr = buf_dma->sg_dma;
+ } else {
+ buf_dma->sg_cpu[nents].ddadr =
+ DDADR(pcdev->dma_chans[i]);
+ }
+
+ /* The next descriptor is the dummy descriptor */
+ DDADR(pcdev->dma_chans[i]) = buf_dma->sg_dma + nents *
+ sizeof(struct pxa_dma_desc);
+
+ DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+ }
}
spin_unlock_irqrestore(&pcdev->lock, flags);
-
}
static void pxa_videobuf_release(struct videobuf_queue *vq,
@@ -354,21 +449,21 @@ static void pxa_videobuf_release(struct videobuf_queue *vq,
#ifdef DEBUG
struct soc_camera_device *icd = vq->priv_data;
- dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
switch (vb->state) {
case VIDEOBUF_ACTIVE:
- dev_dbg(&icd->dev, "%s (active)\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s (active)\n", __func__);
break;
case VIDEOBUF_QUEUED:
- dev_dbg(&icd->dev, "%s (queued)\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s (queued)\n", __func__);
break;
case VIDEOBUF_PREPARED:
- dev_dbg(&icd->dev, "%s (prepared)\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
break;
default:
- dev_dbg(&icd->dev, "%s (unknown)\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
break;
}
#endif
@@ -376,18 +471,42 @@ static void pxa_videobuf_release(struct videobuf_queue *vq,
free_buffer(vq, buf);
}
-static void pxa_camera_dma_irq_y(int channel, void *data)
+static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
+ struct videobuf_buffer *vb,
+ struct pxa_buffer *buf)
+{
+ /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_DONE;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+ wake_up(&vb->done);
+
+ if (list_empty(&pcdev->capture)) {
+ pcdev->active = NULL;
+ DCSR(pcdev->dma_chans[0]) = 0;
+ DCSR(pcdev->dma_chans[1]) = 0;
+ DCSR(pcdev->dma_chans[2]) = 0;
+ CICR0 &= ~CICR0_ENB;
+ return;
+ }
+
+ pcdev->active = list_entry(pcdev->capture.next,
+ struct pxa_buffer, vb.queue);
+}
+
+static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
+ enum pxa_camera_active_dma act_dma)
{
- struct pxa_camera_dev *pcdev = data;
struct pxa_buffer *buf;
unsigned long flags;
- unsigned int status;
+ u32 status, camera_status, overrun;
struct videobuf_buffer *vb;
spin_lock_irqsave(&pcdev->lock, flags);
- status = DCSR(pcdev->dma_chan_y);
- DCSR(pcdev->dma_chan_y) = status;
+ status = DCSR(channel);
+ DCSR(channel) = status | DCSR_ENDINTR;
if (status & DCSR_BUSERR) {
dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");
@@ -405,33 +524,57 @@ static void pxa_camera_dma_irq_y(int channel, void *data)
goto out;
}
+ camera_status = CISR;
+ overrun = CISR_IFO_0;
+ if (pcdev->channels == 3)
+ overrun |= CISR_IFO_1 | CISR_IFO_2;
+ if (camera_status & overrun) {
+ dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
+ /* Stop the Capture Interface */
+ CICR0 &= ~CICR0_ENB;
+ /* Stop DMA */
+ DCSR(channel) = 0;
+ /* Reset the FIFOs */
+ CIFR |= CIFR_RESET_F;
+ /* Enable End-Of-Frame Interrupt */
+ CICR0 &= ~CICR0_EOFM;
+ /* Restart the Capture Interface */
+ CICR0 |= CICR0_ENB;
+ goto out;
+ }
+
vb = &pcdev->active->vb;
buf = container_of(vb, struct pxa_buffer, vb);
WARN_ON(buf->inwork || list_empty(&vb->queue));
- dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
- /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
- list_del_init(&vb->queue);
- vb->state = VIDEOBUF_DONE;
- do_gettimeofday(&vb->ts);
- vb->field_count++;
- wake_up(&vb->done);
-
- if (list_empty(&pcdev->capture)) {
- pcdev->active = NULL;
- DCSR(pcdev->dma_chan_y) = 0;
- CICR0 &= ~CICR0_ENB;
- goto out;
- }
-
- pcdev->active = list_entry(pcdev->capture.next, struct pxa_buffer,
- vb.queue);
+ buf->active_dma &= ~act_dma;
+ if (!buf->active_dma)
+ pxa_camera_wakeup(pcdev, vb, buf);
out:
spin_unlock_irqrestore(&pcdev->lock, flags);
}
+static void pxa_camera_dma_irq_y(int channel, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(channel, pcdev, DMA_Y);
+}
+
+static void pxa_camera_dma_irq_u(int channel, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(channel, pcdev, DMA_U);
+}
+
+static void pxa_camera_dma_irq_v(int channel, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(channel, pcdev, DMA_V);
+}
+
static struct videobuf_queue_ops pxa_videobuf_ops = {
.buf_setup = pxa_videobuf_setup,
.buf_prepare = pxa_videobuf_prepare,
@@ -466,18 +609,18 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
pcdev, pdata);
if (pdata && pdata->init) {
- dev_dbg(pcdev->dev, "%s: Init gpios\n", __FUNCTION__);
+ dev_dbg(pcdev->dev, "%s: Init gpios\n", __func__);
pdata->init(pcdev->dev);
}
if (pdata && pdata->power) {
- dev_dbg(pcdev->dev, "%s: Power on camera\n", __FUNCTION__);
+ dev_dbg(pcdev->dev, "%s: Power on camera\n", __func__);
pdata->power(pcdev->dev, 1);
}
if (pdata && pdata->reset) {
dev_dbg(pcdev->dev, "%s: Releasing camera reset\n",
- __FUNCTION__);
+ __func__);
pdata->reset(pcdev->dev, 1);
}
@@ -507,12 +650,12 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
if (board && board->reset) {
dev_dbg(pcdev->dev, "%s: Asserting camera reset\n",
- __FUNCTION__);
+ __func__);
board->reset(pcdev->dev, 0);
}
if (board && board->power) {
- dev_dbg(pcdev->dev, "%s: Power off camera\n", __FUNCTION__);
+ dev_dbg(pcdev->dev, "%s: Power off camera\n", __func__);
board->power(pcdev->dev, 0);
}
}
@@ -524,8 +667,21 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);
+ if (!status)
+ return IRQ_NONE;
+
CISR = status;
+ if (status & CISR_EOF) {
+ int i;
+ for (i = 0; i < pcdev->channels; i++) {
+ DDADR(pcdev->dma_chans[i]) =
+ pcdev->active->dmas[i].sg_dma;
+ DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+ }
+ CICR0 |= CICR0_EOFM;
+ }
+
return IRQ_HANDLED;
}
@@ -571,8 +727,11 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
/* disable capture, disable interrupts */
CICR0 = 0x3ff;
+
/* Stop DMA engine */
- DCSR(pcdev->dma_chan_y) = 0;
+ DCSR(pcdev->dma_chans[0]) = 0;
+ DCSR(pcdev->dma_chans[1]) = 0;
+ DCSR(pcdev->dma_chans[2]) = 0;
icd->ops->release(icd);
@@ -625,7 +784,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
- u32 cicr0, cicr4 = 0;
+ u32 cicr0, cicr1, cicr4 = 0;
int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
if (ret < 0)
@@ -637,6 +796,8 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
if (!common_flags)
return -EINVAL;
+ pcdev->channels = 1;
+
/* Make choises, based on platform preferences */
if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
(common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
@@ -702,7 +863,26 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
cicr0 = CICR0;
if (cicr0 & CICR0_ENB)
CICR0 = cicr0 & ~CICR0_ENB;
- CICR1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
+
+ cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_YUV422P:
+ pcdev->channels = 3;
+ cicr1 |= CICR1_YCBCR_F;
+ case V4L2_PIX_FMT_YUYV:
+ cicr1 |= CICR1_COLOR_SP_VAL(2);
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ cicr1 |= CICR1_RGB_BPP_VAL(1) | CICR1_RGBT_CONV_VAL(2) |
+ CICR1_TBIT | CICR1_COLOR_SP_VAL(1);
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ cicr1 |= CICR1_COLOR_SP_VAL(1) | CICR1_RGB_BPP_VAL(2);
+ break;
+ }
+
+ CICR1 = cicr1;
CICR2 = 0;
CICR3 = CICR3_LPF_VAL(icd->height - 1) |
CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
@@ -905,16 +1085,36 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->dev = &pdev->dev;
/* request dma */
- pcdev->dma_chan_y = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
- pxa_camera_dma_irq_y, pcdev);
- if (pcdev->dma_chan_y < 0) {
+ pcdev->dma_chans[0] = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
+ pxa_camera_dma_irq_y, pcdev);
+ if (pcdev->dma_chans[0] < 0) {
dev_err(pcdev->dev, "Can't request DMA for Y\n");
err = -ENOMEM;
goto exit_iounmap;
}
- dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chan_y);
+ dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
+
+ pcdev->dma_chans[1] = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
+ pxa_camera_dma_irq_u, pcdev);
+ if (pcdev->dma_chans[1] < 0) {
+ dev_err(pcdev->dev, "Can't request DMA for U\n");
+ err = -ENOMEM;
+ goto exit_free_dma_y;
+ }
+ dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
+
+ pcdev->dma_chans[2] = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
+ pxa_camera_dma_irq_v, pcdev);
+ if (pcdev->dma_chans[0] < 0) {
+ dev_err(pcdev->dev, "Can't request DMA for V\n");
+ err = -ENOMEM;
+ goto exit_free_dma_u;
+ }
+ dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
- DRCMR68 = pcdev->dma_chan_y | DRCMR_MAPVLD;
+ DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD;
+ DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD;
+ DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD;
/* request irq */
err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
@@ -936,7 +1136,11 @@ static int pxa_camera_probe(struct platform_device *pdev)
exit_free_irq:
free_irq(pcdev->irq, pcdev);
exit_free_dma:
- pxa_free_dma(pcdev->dma_chan_y);
+ pxa_free_dma(pcdev->dma_chans[2]);
+exit_free_dma_u:
+ pxa_free_dma(pcdev->dma_chans[1]);
+exit_free_dma_y:
+ pxa_free_dma(pcdev->dma_chans[0]);
exit_iounmap:
iounmap(base);
exit_release:
@@ -956,7 +1160,9 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev)
clk_put(pcdev->clk);
- pxa_free_dma(pcdev->dma_chan_y);
+ pxa_free_dma(pcdev->dma_chans[0]);
+ pxa_free_dma(pcdev->dma_chans[1]);
+ pxa_free_dma(pcdev->dma_chans[2]);
free_irq(pcdev->irq, pcdev);
soc_camera_host_unregister(&pxa_soc_camera_host);
diff --git a/linux/drivers/media/video/saa7110.c b/linux/drivers/media/video/saa7110.c
index eb561ce6c..0692e4bef 100644
--- a/linux/drivers/media/video/saa7110.c
+++ b/linux/drivers/media/video/saa7110.c
@@ -489,7 +489,7 @@ saa7110_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
@@ -497,7 +497,7 @@ saa7110_detect_client (struct i2c_adapter *adapter,
strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client)));
decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
- if (decoder == 0) {
+ if (!decoder) {
kfree(client);
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/saa7111.c b/linux/drivers/media/video/saa7111.c
index df44aed92..917fb2553 100644
--- a/linux/drivers/media/video/saa7111.c
+++ b/linux/drivers/media/video/saa7111.c
@@ -503,7 +503,7 @@ saa7111_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/saa7114.c b/linux/drivers/media/video/saa7114.c
index ebf42cf9e..158bd123c 100644
--- a/linux/drivers/media/video/saa7114.c
+++ b/linux/drivers/media/video/saa7114.c
@@ -842,7 +842,7 @@ saa7114_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/saa7115.c b/linux/drivers/media/video/saa7115.c
index a5ae60c7b..fc4c17bbd 100644
--- a/linux/drivers/media/video/saa7115.c
+++ b/linux/drivers/media/video/saa7115.c
@@ -1461,19 +1461,25 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
/* ----------------------------------------------------------------------- */
-static int saa7115_probe(struct i2c_client *client)
+static int saa7115_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct saa711x_state *state;
int i;
char name[17];
- u8 chip_id;
+ char chip_id;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ int autodetect = !id || id->driver_data == 1;
+#endif
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "saa7115");
+#endif
for (i = 0; i < 0x0f; i++) {
saa711x_write(client, 0, i);
name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
@@ -1482,8 +1488,7 @@ static int saa7115_probe(struct i2c_client *client)
}
name[i] = '\0';
- saa711x_write(client, 0, 5);
- chip_id = saa711x_read(client, 0) & 0x0f;
+ chip_id = name[5];
/* Check whether this chip is part of the saa711x series */
if (memcmp(name, "1f711", 5)) {
@@ -1492,8 +1497,16 @@ static int saa7115_probe(struct i2c_client *client)
return -ENODEV;
}
- snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
- v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ /* Safety check */
+ if (!autodetect && id->name[6] != chip_id) {
+ v4l_warn(client, "found saa711%c while %s was expected\n",
+ chip_id, id->name);
+ }
+#endif
+ snprintf(client->name, sizeof(client->name), "saa711%c", chip_id);
+ v4l_info(client, "saa711%c found (%s) @ 0x%x (%s)\n", chip_id, name,
+ client->addr << 1, client->adapter->name);
state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
i2c_set_clientdata(client, state);
@@ -1509,19 +1522,19 @@ static int saa7115_probe(struct i2c_client *client)
state->hue = 0;
state->sat = 64;
switch (chip_id) {
- case 1:
+ case '1':
state->ident = V4L2_IDENT_SAA7111;
break;
- case 3:
+ case '3':
state->ident = V4L2_IDENT_SAA7113;
break;
- case 4:
+ case '4':
state->ident = V4L2_IDENT_SAA7114;
break;
- case 5:
+ case '5':
state->ident = V4L2_IDENT_SAA7115;
break;
- case 8:
+ case '8':
state->ident = V4L2_IDENT_SAA7118;
break;
default:
@@ -1563,6 +1576,19 @@ static int saa7115_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa7115_id[] = {
+ { "saa711x", 1 }, /* autodetect */
+ { "saa7111", 0 },
+ { "saa7113", 0 },
+ { "saa7114", 0 },
+ { "saa7115", 0 },
+ { "saa7118", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7115_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa7115",
.driverid = I2C_DRIVERID_SAA711X,
@@ -1572,6 +1598,9 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
#ifdef I2C_CLASS_TV_ANALOG
.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa7115_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
diff --git a/linux/drivers/media/video/saa7127.c b/linux/drivers/media/video/saa7127.c
index ff2e70833..a73ae00af 100644
--- a/linux/drivers/media/video/saa7127.c
+++ b/linux/drivers/media/video/saa7127.c
@@ -679,7 +679,8 @@ static int saa7127_command(struct i2c_client *client,
/* ----------------------------------------------------------------------- */
-static int saa7127_probe(struct i2c_client *client)
+static int saa7127_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct saa7127_state *state;
struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
@@ -689,8 +690,10 @@ static int saa7127_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "saa7127");
+#endif
v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
client->addr << 1);
@@ -758,12 +761,23 @@ static int saa7127_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static struct i2c_device_id saa7127_id[] = {
+ { "saa7127", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa7127_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "saa7127",
.driverid = I2C_DRIVERID_SAA7127,
.command = saa7127_command,
.probe = saa7127_probe,
.remove = saa7127_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa7127_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig
index e086f14d5..83f076abc 100644
--- a/linux/drivers/media/video/saa7134/Kconfig
+++ b/linux/drivers/media/video/saa7134/Kconfig
@@ -27,6 +27,7 @@ config VIDEO_SAA7134_ALSA
config VIDEO_SAA7134_DVB
tristate "DVB/ATSC Support for saa7134 based TV cards"
depends on VIDEO_SAA7134 && DVB_CORE
+ depends on HOTPLUG # due to FW_LOADER
select VIDEOBUF_DVB
select FW_LOADER
select DVB_PLL if !DVB_FE_CUSTOMISE
@@ -35,9 +36,9 @@ config VIDEO_SAA7134_DVB
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
- select DVB_TDA827X if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/linux/drivers/media/video/saa7134/Makefile b/linux/drivers/media/video/saa7134/Makefile
index 9aff937ba..3dbaa19a6 100644
--- a/linux/drivers/media/video/saa7134/Makefile
+++ b/linux/drivers/media/video/saa7134/Makefile
@@ -11,5 +11,6 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/video/saa7134/saa7134-alsa.c b/linux/drivers/media/video/saa7134/saa7134-alsa.c
index 121b50e88..58670f9ea 100644
--- a/linux/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/linux/drivers/media/video/saa7134/saa7134-alsa.c
@@ -969,10 +969,8 @@ static void snd_saa7134_free(struct snd_card * card)
if (chip->dev->dmasound.priv_data == NULL)
return;
- if (chip->irq >= 0) {
- synchronize_irq(chip->irq);
+ if (chip->irq >= 0)
free_irq(chip->irq, &chip->dev->dmasound);
- }
chip->dev->dmasound.priv_data = NULL;
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index 3bee2d71c..49bf24e7b 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -30,6 +30,7 @@
#include "tuner-xc2028.h"
#include <media/v4l2-common.h>
#include <media/tveeprom.h>
+#include "tea5767.h"
/* commly used strings */
static char name_mute[] = "mute";
@@ -46,6 +47,9 @@ static char name_svideo[] = "S-Video";
/* ------------------------------------------------------------------ */
/* board config info */
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
struct saa7134_board saa7134_boards[] = {
[SAA7134_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
@@ -1049,7 +1053,7 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_MANLI_MTV002] = {
/* Ognjen Nastic <ognjen@logosoft.ba> */
- .name = "Manli MuchTV M-TV002/Behold TV 403 FM",
+ .name = "Manli MuchTV M-TV002",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
.radio_type = UNSET,
@@ -1076,7 +1080,7 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_MANLI_MTV001] = {
/* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
- .name = "Manli MuchTV M-TV001/Behold TV 401",
+ .name = "Manli MuchTV M-TV001",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
.radio_type = UNSET,
@@ -2198,6 +2202,8 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_BEHOLD_409FM] = {
/* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 409 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -2205,6 +2211,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -3122,7 +3129,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_type = TUNER_PHILIPS_TD1316, /* untested */
.radio_type = TUNER_TEA5767, /* untested */
.tuner_addr = ADDR_UNSET,
- .radio_addr = ADDR_UNSET,
+ .radio_addr = 0x60,
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
@@ -3615,12 +3622,15 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_BEHOLD_401] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 401",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FQ1216ME,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3641,12 +3651,15 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_403] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 403",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FQ1216ME,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3663,12 +3676,15 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_BEHOLD_403FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 403 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FQ1216ME,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3689,6 +3705,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_405] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 405",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3696,6 +3714,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3713,6 +3732,8 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_BEHOLD_405FM] = {
/* Sergey <skiv@orel.ru> */
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 405 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3720,6 +3741,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3740,6 +3762,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_407] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 407",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3747,7 +3771,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .gpiomask = 0xc0c000,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3767,6 +3791,8 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_BEHOLD_407FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 407 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3774,7 +3800,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .gpiomask = 0xc0c000,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3799,6 +3825,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_409] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 409",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3806,6 +3834,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -3822,6 +3851,8 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_BEHOLD_505FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 505 FM/RDS",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3829,6 +3860,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -3853,6 +3885,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_507_9FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3860,6 +3894,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -3880,6 +3915,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV Columbus TVFM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_ALPS_TSBE5_PAL,
@@ -3887,23 +3924,28 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x000A8004,
.inputs = {{
.name = name_tv,
.vmux = 3,
.amux = TV,
.tv = 1,
- },{
+ .gpio = 0x000A8004,
+ }, {
.name = name_comp1,
.vmux = 1,
.amux = LINE1,
- },{
+ .gpio = 0x000A8000,
+ }, {
.name = name_svideo,
.vmux = 8,
.amux = LINE1,
- }},
+ .gpio = 0x000A8000,
+ } },
.radio = {
.name = name_radio,
.amux = LINE2,
+ .gpio = 0x000A8000,
},
},
[SAA7134_BOARD_BEHOLD_607_9FM] = {
@@ -4251,6 +4293,36 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
} },
},
+ [SAA7134_BOARD_BEHOLD_H6] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ .name = "Beholder BeholdTV H6",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ /* no DVB support for now */
+ /* .mpeg = SAA7134_MPEG_DVB, */
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -5201,6 +5273,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = 0x5ace,
.subdevice = 0x6193,
.driver_data = SAA7134_BOARD_BEHOLD_M6,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6191,
+ .driver_data = SAA7134_BOARD_BEHOLD_M6,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -5250,6 +5328,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0xc900,
.driver_data = SAA7134_BOARD_VIDEOMATE_T750,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6290,
+ .driver_data = SAA7134_BOARD_BEHOLD_H6,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5574,7 +5658,6 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_CARDBUS:
case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
case SAA7134_BOARD_AVERMEDIA_M115:
- case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
case SAA7134_BOARD_AVERMEDIA_A16D:
#if 1
/* power-down tuner chip */
@@ -5587,6 +5670,20 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
msleep(10);
break;
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+#if 1
+ /* power-down tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0);
+#endif
+ msleep(10);
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0x000A8004);
+ msleep(10);
+ /* remote via GPIO */
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
case SAA7134_BOARD_RTD_VFG7350:
/*
@@ -5632,20 +5729,87 @@ int saa7134_board_init1(struct saa7134_dev *dev)
return 0;
}
+static void saa7134_tuner_setup(struct saa7134_dev *dev)
+{
+ struct tuner_setup tun_setup;
+ unsigned int mode_mask = T_RADIO |
+ T_ANALOG_TV |
+ T_DIGITAL_TV;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
+ tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ if (saa7134_boards[dev->board].radio_type != UNSET) {
+ tun_setup.type = saa7134_boards[dev->board].radio_type;
+ tun_setup.addr = saa7134_boards[dev->board].radio_addr;
+
+ tun_setup.mode_mask = T_RADIO;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+ if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) {
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+ tun_setup.config = saa7134_boards[dev->board].tuner_config;
+ tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ tun_setup.mode_mask = mode_mask;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
+ if (dev->tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+ &tda9887_cfg);
+ }
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ memset(&xc2028_cfg, 0, sizeof(ctl));
+ memset(&ctl, 0, sizeof(ctl));
+
+ ctl.fname = XC2028_DEFAULT_FIRMWARE;
+ ctl.max_len = 64;
+
+ switch (dev->board) {
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ ctl.demod = XC3028_FE_ZARLINK456;
+ break;
+ default:
+ ctl.demod = XC3028_FE_OREN538;
+ ctl.mts = 1;
+ }
+
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+ }
+}
+
/* stuff which needs working i2c */
int saa7134_board_init2(struct saa7134_dev *dev)
{
unsigned char buf;
int board;
- struct tuner_setup tun_setup;
- tun_setup.config = 0;
- tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
switch (dev->board) {
case SAA7134_BOARD_BMK_MPEX_NOTUNER:
case SAA7134_BOARD_BMK_MPEX_TUNER:
dev->i2c_client.addr = 0x60;
- board = (i2c_master_recv(&dev->i2c_client,&buf,0) < 0)
+ board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0)
? SAA7134_BOARD_BMK_MPEX_NOTUNER
: SAA7134_BOARD_BMK_MPEX_TUNER;
if (board == dev->board)
@@ -5655,21 +5819,9 @@ int saa7134_board_init2(struct saa7134_dev *dev)
saa7134_boards[dev->board].name);
dev->tuner_type = saa7134_boards[dev->board].tuner_type;
- if (TUNER_ABSENT != dev->tuner_type) {
- tun_setup.mode_mask = T_RADIO |
- T_ANALOG_TV |
- T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = ADDR_UNSET;
- tun_setup.tuner_callback = saa7134_tuner_callback;
-
- saa7134_i2c_call_clients(dev,
- TUNER_SET_TYPE_ADDR,
- &tun_setup);
- }
break;
case SAA7134_BOARD_MD7134:
- {
+ {
u8 subaddr;
u8 data[3];
int ret, tuner_t;
@@ -5722,30 +5874,8 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
- if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
-
- dev->tda9887_conf = TDA9887_PRESENT |
- TDA9887_PORT1_ACTIVE |
- TDA9887_PORT2_ACTIVE;
-
- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
- &tda9887_cfg);
- }
-
- tun_setup.mode_mask = T_RADIO |
- T_ANALOG_TV |
- T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = ADDR_UNSET;
-
- saa7134_i2c_call_clients(dev,
- TUNER_SET_TYPE_ADDR, &tun_setup);
- }
break;
+ }
case SAA7134_BOARD_PHILIPS_EUROPA:
if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) {
/* Reconfigure board as Snake reference design */
@@ -5757,43 +5887,43 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ {
+
/* The Philips EUROPA based hybrid boards have the tuner connected through
* the channel decoder. We have to make it transparent to find it
*/
- {
u8 data[] = { 0x07, 0x02};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = dev->tuner_addr;
-
- saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
- }
break;
+ }
case SAA7134_BOARD_PHILIPS_TIGER:
case SAA7134_BOARD_PHILIPS_TIGER_S:
- {
+ {
u8 data[] = { 0x3c, 0x33, 0x60};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
- if(dev->autodetected && (dev->eedata[0x49] == 0x50)) {
+ if (dev->autodetected && (dev->eedata[0x49] == 0x50)) {
dev->board = SAA7134_BOARD_PHILIPS_TIGER_S;
printk(KERN_INFO "%s: Reconfigured board as %s\n",
dev->name, saa7134_boards[dev->board].name);
}
- if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = TUNER_PHILIPS_TDA8290;
- tun_setup.addr = 0x4b;
- tun_setup.config = 2;
+ if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
+ dev->tuner_type = TUNER_PHILIPS_TDA8290;
+
+ saa7134_tuner_setup(dev);
- saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
data[2] = 0x68;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ /* Tuner setup is handled before I2C transfer.
+ Due to that, there's no need to do it later
+ */
+ return 0;
}
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
hauppauge_eeprom(dev, dev->eedata+0x80);
/* break intentionally omitted */
@@ -5806,52 +5936,55 @@ int saa7134_board_init2(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
case SAA7134_BOARD_CREATIX_CTX953:
+ {
/* this is a hybrid board, initialize to analog mode
* and configure firmware eeprom address
*/
- {
u8 data[] = { 0x3c, 0x33, 0x60};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_FLYDVB_TRIO:
- {
+ {
u8 data[] = { 0x3c, 0x33, 0x62};
struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+ {
/* initialize analog mode */
- {
u8 data[] = { 0x3c, 0x33, 0x6a};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
case SAA7134_BOARD_CINERGY_HT_PCI:
+ {
/* initialize analog mode */
- {
u8 data[] = { 0x3c, 0x33, 0x68};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_KWORLD_ATSC110:
- {
- /* enable tuner */
- int i;
- static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
- dev->i2c_client.addr = 0x0a;
- for (i = 0; i < 5; i++)
- if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2))
- printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
- dev->name, i);
- }
+ {
+ /* enable tuner */
+ int i;
+ static const u8 buffer [] = { 0x10, 0x12, 0x13, 0x04, 0x16,
+ 0x00, 0x14, 0x04, 0x17, 0x00 };
+ dev->i2c_client.addr = 0x0a;
+ for (i = 0; i < 5; i++)
+ if (2 != i2c_master_send(&dev->i2c_client,
+ &buffer[i*2], 2))
+ printk(KERN_WARNING
+ "%s: Unable to enable tuner(%i).\n",
+ dev->name, i);
break;
+ }
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
/* The T200 and the T200A share the same pci id. Consequently,
@@ -5875,32 +6008,23 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
}
break;
- }
-
- if (dev->tuner_type == TUNER_XC2028) {
- struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ {
+ struct v4l2_priv_tun_config tea5767_cfg;
+ struct tea5767_ctrl ctl;
- memset(&xc2028_cfg, 0, sizeof(ctl));
+ dev->i2c_client.addr = 0xC0;
+ /* set TEA5767(analog FM) defines */
memset(&ctl, 0, sizeof(ctl));
-
- ctl.fname = XC2028_DEFAULT_FIRMWARE;
- ctl.max_len = 64;
-
- switch (dev->board) {
- case SAA7134_BOARD_AVERMEDIA_A16D:
- ctl.demod = XC3028_FE_ZARLINK456;
- break;
- default:
- ctl.demod = XC3028_FE_OREN538;
- ctl.mts = 1;
- }
-
- xc2028_cfg.tuner = TUNER_XC2028;
- xc2028_cfg.priv = &ctl;
-
- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+ ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+ tea5767_cfg.tuner = TUNER_TEA5767;
+ tea5767_cfg.priv = &ctl;
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg);
+ break;
}
+ } /* switch() */
+
+ saa7134_tuner_setup(dev);
return 0;
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c
index 7296eeba0..9ed2997f7 100644
--- a/linux/drivers/media/video/saa7134/saa7134-core.c
+++ b/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -960,7 +960,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
struct saa7134_dev *dev;
struct saa7134_mpeg_ops *mops;
int err;
- int mask;
if (saa7134_devcount == SAA7134_MAXBOARDS)
return -ENOMEM;
@@ -1161,11 +1160,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (TUNER_ABSENT != dev->tuner_type)
saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
- if (card(dev).gpiomask != 0) {
- mask = card(dev).gpiomask;
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, 0);
- }
return 0;
fail4:
diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index 165b4b850..a5a2d5905 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -65,6 +65,8 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off).");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
#define dprintk(fmt, arg...) do { if (debug) \
printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0)
@@ -539,19 +541,23 @@ static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
return 0;
}
-static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *cdec_conf,
- struct tda827x_config *tuner_conf)
+static int configure_tda827x_fe(struct saa7134_dev *dev,
+ struct tda1004x_config *cdec_conf,
+ struct tda827x_config *tuner_conf)
{
dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (cdec_conf->i2c_gate)
dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
- if (dvb_attach(tda827x_attach, dev->dvb.frontend, cdec_conf->tuner_address,
- &dev->i2c_adap, tuner_conf) == NULL) {
- wprintk("no tda827x tuner found at addr: %02x\n",
+ if (dvb_attach(tda827x_attach, dev->dvb.frontend,
+ cdec_conf->tuner_address,
+ &dev->i2c_adap, tuner_conf))
+ return 0;
+
+ wprintk("no tda827x tuner found at addr: %02x\n",
cdec_conf->tuner_address);
- }
}
+ return -EINVAL;
}
/* ------------------------------------------------------------------ */
@@ -852,6 +858,14 @@ static struct tda10086_config flydvbs = {
.demod_address = 0x0e,
.invert = 0,
.diseqc_tone = 0,
+ .xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct tda10086_config sd1878_4m = {
+ .demod_address = 0x0e,
+ .invert = 0,
+ .diseqc_tone = 0,
+ .xtal_freq = TDA10086_XTAL_4M,
};
/* ------------------------------------------------------------------
@@ -990,7 +1004,9 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
- configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
@@ -1015,36 +1031,52 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_KWORLD_DVBT_210:
- configure_tda827x_fe(dev, &kworld_dvb_t_210_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_TIGER:
- configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &philips_tiger_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PINNACLE_PCTV_310i:
- configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, &tda827x_cfg_1);
+ if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config,
+ &tda827x_cfg_1) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
- configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, &tda827x_cfg_1);
+ if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config,
+ &tda827x_cfg_1) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
- configure_tda827x_fe(dev, &asus_p7131_dual_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_FLYDVBT_LR301:
- configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_FLYDVB_TRIO:
- if(! use_frontend) { /* terrestrial */
- configure_tda827x_fe(dev, &lifeview_trio_config, &tda827x_cfg_0);
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &lifeview_trio_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
} else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
+ goto dettach_frontend;
}
if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
0x08, 0, 0) == NULL) {
wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
+ goto dettach_frontend;
}
}
}
@@ -1060,15 +1092,20 @@ static int dvb_init(struct saa7134_dev *dev)
&ads_duo_cfg) == NULL) {
wprintk("no tda827x tuner found at addr: %02x\n",
ads_tech_duo_config.tuner_address);
+ goto dettach_frontend;
}
}
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
- configure_tda827x_fe(dev, &tevion_dvbt220rf_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_MEDION_MD8800_QUADRO:
if (!use_frontend) { /* terrestrial */
- configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
} else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach,
&flydvbs, &dev->i2c_adap);
@@ -1079,16 +1116,20 @@ static int dvb_init(struct saa7134_dev *dev)
struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
if (dvb_attach(tda826x_attach, dev->dvb.frontend,
- 0x60, &dev->i2c_adap, 0) == NULL)
+ 0x60, &dev->i2c_adap, 0) == NULL) {
wprintk("%s: Medion Quadro, no tda826x "
"found !\n", __func__);
+ goto dettach_frontend;
+ }
if (dev_id != 0x08) {
/* we need to open the i2c gate (we know it exists) */
fe->ops.i2c_gate_ctrl(fe, 1);
if (dvb_attach(isl6405_attach, fe,
- &dev->i2c_adap, 0x08, 0, 0) == NULL)
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
wprintk("%s: Medion Quadro, no ISL6405 "
"found !\n", __func__);
+ goto dettach_frontend;
+ }
if (dev_id == 0x07) {
/* fire up the 2nd section of the LNB supply since
we can't do this from the other section */
@@ -1110,19 +1151,17 @@ static int dvb_init(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
+ if (dev->dvb.frontend)
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
NULL, DVB_PLL_TDHU2);
- }
break;
case SAA7134_BOARD_KWORLD_ATSC110:
dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
&dev->i2c_adap);
- if (dev->dvb.frontend) {
+ if (dev->dvb.frontend)
dvb_attach(simple_tuner_attach, dev->dvb.frontend,
&dev->i2c_adap, 0x61,
TUNER_PHILIPS_TUV1236D);
- }
break;
case SAA7134_BOARD_FLYDVBS_LR300:
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
@@ -1131,10 +1170,12 @@ static int dvb_init(struct saa7134_dev *dev)
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
wprintk("%s: No tda826x found!\n", __func__);
+ goto dettach_frontend;
}
if (dvb_attach(isl6421_attach, dev->dvb.frontend,
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
wprintk("%s: No ISL6421 found!\n", __func__);
+ goto dettach_frontend;
}
}
break;
@@ -1161,43 +1202,65 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
- configure_tda827x_fe(dev, &cinergy_ht_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &cinergy_ht_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_CINERGY_HT_PCI:
- configure_tda827x_fe(dev, &cinergy_ht_pci_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &cinergy_ht_pci_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_TIGER_S:
- configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_ASUS_P7131_4871:
- configure_tda827x_fe(dev, &asus_p7131_4871_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &asus_p7131_4871_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
- configure_tda827x_fe(dev, &avermedia_super_007_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &avermedia_super_007_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
- configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, &tda827x_cfg_2_sw42);
+ if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config,
+ &tda827x_cfg_2_sw42) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_PHILIPS_SNAKE:
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
&dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
- &dev->i2c_adap, 0) == NULL)
+ &dev->i2c_adap, 0) == NULL) {
wprintk("%s: No tda826x found!\n", __func__);
+ goto dettach_frontend;
+ }
if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
- &dev->i2c_adap, 0, 0) == NULL)
+ &dev->i2c_adap, 0, 0) == NULL) {
wprintk("%s: No lnbp21 found!\n", __func__);
+ goto dettach_frontend;
+ }
}
break;
case SAA7134_BOARD_CREATIX_CTX953:
- configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+ if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+ &tda827x_cfg_0) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
- configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
+ if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
#if 0
@@ -1211,20 +1274,24 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_MD7134_BRIDGE_2:
dev->dvb.frontend = dvb_attach(tda10086_attach,
- &flydvbs, &dev->i2c_adap);
+ &sd1878_4m, &dev->i2c_adap);
if (dev->dvb.frontend) {
struct dvb_frontend *fe;
if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL)
+ &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
wprintk("%s: MD7134 DVB-S, no SD1878 "
"found !\n", __func__);
+ goto dettach_frontend;
+ }
/* we need to open the i2c gate (we know it exists) */
fe = dev->dvb.frontend;
fe->ops.i2c_gate_ctrl(fe, 1);
if (dvb_attach(isl6405_attach, fe,
- &dev->i2c_adap, 0x08, 0, 0) == NULL)
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
wprintk("%s: MD7134 DVB-S, no ISL6405 "
"found !\n", __func__);
+ goto dettach_frontend;
+ }
fe->ops.i2c_gate_ctrl(fe, 0);
dev->original_set_voltage = fe->ops.set_voltage;
fe->ops.set_voltage = md8800_set_voltage;
@@ -1251,10 +1318,7 @@ static int dvb_init(struct saa7134_dev *dev)
if (!fe) {
printk(KERN_ERR "%s/2: xc3028 attach failed\n",
dev->name);
- dvb_frontend_detach(dev->dvb.frontend);
- dvb_unregister_frontend(dev->dvb.frontend);
- dev->dvb.frontend = NULL;
- return -1;
+ goto dettach_frontend;
}
}
@@ -1264,7 +1328,8 @@ static int dvb_init(struct saa7134_dev *dev)
}
/* register everything else */
- ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+ ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
+ adapter_nr);
/* this sequence is necessary to make the tda1004x load its firmware
* and to enter analog mode of hybrid boards
@@ -1278,6 +1343,13 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend);
}
return ret;
+
+dettach_frontend:
+ if (dev->dvb.frontend)
+ dvb_frontend_detach(dev->dvb.frontend);
+ dev->dvb.frontend = NULL;
+
+ return -1;
}
static int dvb_fini(struct saa7134_dev *dev)
@@ -1309,7 +1381,8 @@ static int dvb_fini(struct saa7134_dev *dev)
}
}
}
- videobuf_dvb_unregister(&dev->dvb);
+ if (dev->dvb.frontend)
+ videobuf_dvb_unregister(&dev->dvb);
return 0;
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index b83e910c3..b8ecaa623 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -172,8 +172,7 @@ ts_mmap(struct file *file, struct vm_area_struct * vma)
static int empress_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
@@ -213,7 +212,7 @@ static int empress_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int empress_enum_fmt_cap(struct file *file, void *priv,
+static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (f->index != 0)
@@ -225,7 +224,7 @@ static int empress_enum_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int empress_g_fmt_cap(struct file *file, void *priv,
+static int empress_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
@@ -239,7 +238,7 @@ static int empress_g_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int empress_s_fmt_cap(struct file *file, void *priv,
+static int empress_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
@@ -363,9 +362,9 @@ static struct video_device saa7134_empress_template =
.minor = -1,
.vidioc_querycap = empress_querycap,
- .vidioc_enum_fmt_cap = empress_enum_fmt_cap,
- .vidioc_s_fmt_cap = empress_s_fmt_cap,
- .vidioc_g_fmt_cap = empress_g_fmt_cap,
+ .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap,
.vidioc_reqbufs = empress_reqbufs,
.vidioc_querybuf = empress_querybuf,
.vidioc_qbuf = empress_qbuf,
@@ -419,7 +418,7 @@ static int empress_init(struct saa7134_dev *dev)
{
int err;
- dprintk("%s: %s\n",dev->name,__FUNCTION__);
+ dprintk("%s: %s\n",dev->name,__func__);
dev->empress_dev = video_device_alloc();
if (NULL == dev->empress_dev)
return -ENOMEM;
@@ -467,7 +466,7 @@ static int empress_init(struct saa7134_dev *dev)
static int empress_fini(struct saa7134_dev *dev)
{
- dprintk("%s: %s\n",dev->name,__FUNCTION__);
+ dprintk("%s: %s\n",dev->name,__func__);
if (NULL == dev->empress_dev)
return 0;
diff --git a/linux/drivers/media/video/saa7134/saa7134-i2c.c b/linux/drivers/media/video/saa7134/saa7134-i2c.c
index fda6d44cd..c222313fc 100644
--- a/linux/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c
@@ -140,6 +140,8 @@ static inline int i2c_is_busy(enum i2c_status status)
{
switch (status) {
case BUSY:
+ case TO_SCL:
+ case TO_ARB:
return true;
default:
return false;
@@ -327,8 +329,6 @@ static u32 functionality(struct i2c_adapter *adap)
static int attach_inform(struct i2c_client *client)
{
struct saa7134_dev *dev = client->adapter->algo_data;
- int tuner = dev->tuner_type;
- struct tuner_setup tun_setup;
d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
@@ -357,46 +357,6 @@ static int attach_inform(struct i2c_client *client)
}
}
- if (!client->driver->command)
- return 0;
-
- if (saa7134_boards[dev->board].radio_type != UNSET) {
-
- tun_setup.type = saa7134_boards[dev->board].radio_type;
- tun_setup.addr = saa7134_boards[dev->board].radio_addr;
-
- if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) {
- tun_setup.mode_mask = T_RADIO;
-
- client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
-
- if (tuner != UNSET) {
- tun_setup.type = tuner;
- tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
- tun_setup.config = saa7134_boards[dev->board].tuner_config;
- tun_setup.tuner_callback = saa7134_tuner_callback;
-
- if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
-
- tun_setup.mode_mask = T_ANALOG_TV;
-
- client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
- }
-
- if (tuner == TUNER_TDA9887) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
-
- client->driver->command(client, TUNER_SET_CONFIG,
- &tda9887_cfg);
- }
- }
-
-
return 0;
}
diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c
index 225f075e5..45c4c8125 100644
--- a/linux/drivers/media/video/saa7134/saa7134-input.c
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c
@@ -331,6 +331,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
+ ir_codes = ir_codes_manli;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ polling = 50; /* ms */
+ break;
case SAA7134_BOARD_BEHOLD_409FM:
case SAA7134_BOARD_BEHOLD_401:
case SAA7134_BOARD_BEHOLD_403:
@@ -343,7 +348,13 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_505FM:
case SAA7134_BOARD_BEHOLD_507_9FM:
ir_codes = ir_codes_manli;
- mask_keycode = 0x001f00;
+ mask_keycode = 0x003f00;
+ mask_keyup = 0x004000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ ir_codes = ir_codes_behold_columbus;
+ mask_keycode = 0x003f00;
mask_keyup = 0x004000;
polling = 50; // ms
break;
@@ -530,6 +541,7 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
break;
case SAA7134_BOARD_BEHOLD_607_9FM:
case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_H6:
snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
ir->get_key = get_key_beholdm6xx;
ir->ir_codes = ir_codes_behold;
diff --git a/linux/drivers/media/video/saa7134/saa7134-reg.h b/linux/drivers/media/video/saa7134/saa7134-reg.h
index 86f5eefdb..258792c17 100644
--- a/linux/drivers/media/video/saa7134/saa7134-reg.h
+++ b/linux/drivers/media/video/saa7134/saa7134-reg.h
@@ -353,6 +353,7 @@
/* I2S output */
#define SAA7134_I2S_AUDIO_OUTPUT 0x1c0
+#define SAA7134_I2S_AUDIO_CONTROL 0x591
/* test modes */
#define SAA7134_SPECIAL_MODE 0x1d0
diff --git a/linux/drivers/media/video/saa7134/saa7134-tvaudio.c b/linux/drivers/media/video/saa7134/saa7134-tvaudio.c
index 0d24ab598..89f64f927 100644
--- a/linux/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/linux/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -928,13 +928,25 @@ void saa7134_enable_i2s(struct saa7134_dev *dev)
if (!card_is_empress(dev))
return;
- i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
- /* enable I2S audio output for the mpeg encoder */
- saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80);
- saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format);
- saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F);
- saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01);
+ switch (dev->board) {
+ case SAA7134_BOARD_BEHOLD_M6:
+ /* configure GPIO for out audio */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0E000000, 0x00000000);
+ /* Set I2S format */
+ saa_writeb(SAA7134_I2S_AUDIO_CONTROL, 0x00);
+ /* Start I2S */
+ saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11);
+ break;
+ default:
+ i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
+
+ /* enable I2S audio output for the mpeg encoder */
+ saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80);
+ saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format);
+ saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F);
+ saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01);
+ }
}
int saa7134_tvaudio_rx2mode(u32 rx)
diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c
index 3b7774305..353679fef 100644
--- a/linux/drivers/media/video/saa7134/saa7134-video.c
+++ b/linux/drivers/media/video/saa7134/saa7134-video.c
@@ -1496,7 +1496,7 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma)
/* ------------------------------------------------------------------ */
-static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv,
+static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
@@ -1523,7 +1523,7 @@ static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv,
return 0;
}
-static int saa7134_g_fmt_cap(struct file *file, void *priv,
+static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
@@ -1539,7 +1539,7 @@ static int saa7134_g_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int saa7134_g_fmt_overlay(struct file *file, void *priv,
+static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
@@ -1553,7 +1553,7 @@ static int saa7134_g_fmt_overlay(struct file *file, void *priv,
return 0;
}
-static int saa7134_try_fmt_cap(struct file *file, void *priv,
+static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
@@ -1604,7 +1604,7 @@ static int saa7134_try_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int saa7134_try_fmt_overlay(struct file *file, void *priv,
+static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
@@ -1618,13 +1618,13 @@ static int saa7134_try_fmt_overlay(struct file *file, void *priv,
return verify_preview(dev, &f->fmt.win);
}
-static int saa7134_s_fmt_cap(struct file *file, void *priv,
+static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
int err;
- err = saa7134_try_fmt_cap(file, priv, f);
+ err = saa7134_try_fmt_vid_cap(file, priv, f);
if (0 != err)
return err;
@@ -1635,13 +1635,13 @@ static int saa7134_s_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int saa7134_s_fmt_overlay(struct file *file, void *priv,
+static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
int err;
- unsigned int flags;
+ unsigned long flags;
if (saa7134_no_overlay > 0) {
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
@@ -2035,7 +2035,7 @@ static int saa7134_s_priority(struct file *file, void *f,
return v4l2_prio_change(&dev->prio, &fh->prio, prio);
}
-static int saa7134_enum_fmt_cap(struct file *file, void *priv,
+static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (f->index >= FORMATS)
@@ -2049,7 +2049,7 @@ static int saa7134_enum_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int saa7134_enum_fmt_overlay(struct file *file, void *priv,
+static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (saa7134_no_overlay > 0) {
@@ -2068,7 +2068,7 @@ static int saa7134_enum_fmt_overlay(struct file *file, void *priv,
return 0;
}
-static int saa7134_enum_fmt_vbi(struct file *file, void *priv,
+static int saa7134_enum_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (0 != f->index)
@@ -2359,18 +2359,18 @@ struct video_device saa7134_video_template =
.fops = &video_fops,
.minor = -1,
.vidioc_querycap = saa7134_querycap,
- .vidioc_enum_fmt_cap = saa7134_enum_fmt_cap,
- .vidioc_g_fmt_cap = saa7134_g_fmt_cap,
- .vidioc_try_fmt_cap = saa7134_try_fmt_cap,
- .vidioc_s_fmt_cap = saa7134_s_fmt_cap,
- .vidioc_enum_fmt_overlay = saa7134_enum_fmt_overlay,
- .vidioc_g_fmt_overlay = saa7134_g_fmt_overlay,
- .vidioc_try_fmt_overlay = saa7134_try_fmt_overlay,
- .vidioc_s_fmt_overlay = saa7134_s_fmt_overlay,
- .vidioc_enum_fmt_vbi = saa7134_enum_fmt_vbi,
- .vidioc_g_fmt_vbi = saa7134_try_get_set_fmt_vbi,
- .vidioc_try_fmt_vbi = saa7134_try_get_set_fmt_vbi,
- .vidioc_s_fmt_vbi = saa7134_try_get_set_fmt_vbi,
+ .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = saa7134_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = saa7134_s_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_overlay = saa7134_enum_fmt_vid_overlay,
+ .vidioc_g_fmt_vid_overlay = saa7134_g_fmt_vid_overlay,
+ .vidioc_try_fmt_vid_overlay = saa7134_try_fmt_vid_overlay,
+ .vidioc_s_fmt_vid_overlay = saa7134_s_fmt_vid_overlay,
+ .vidioc_enum_fmt_vbi_cap = saa7134_enum_fmt_vbi_cap,
+ .vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_g_audio = saa7134_g_audio,
.vidioc_s_audio = saa7134_s_audio,
.vidioc_cropcap = saa7134_cropcap,
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index c8fb28d99..2aa30895f 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -270,6 +270,7 @@ struct saa7134_format {
#define SAA7134_BOARD_VIDEOMATE_T750 139
#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140
#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
+#define SAA7134_BOARD_BEHOLD_H6 142
#define SAA7134_MAXBOARDS 8
diff --git a/linux/drivers/media/video/saa717x.c b/linux/drivers/media/video/saa717x.c
new file mode 100644
index 000000000..adcc7adc5
--- /dev/null
+++ b/linux/drivers/media/video/saa717x.c
@@ -0,0 +1,1547 @@
+/*
+ * saa717x - Philips SAA717xHL video decoder driver
+ *
+ * Based on the saa7115 driver
+ *
+ * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
+ * - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
+ *
+ * Changes by T.Adachi (tadachi@tadachi-net.com)
+ * - support audio, video scaler etc, and checked the initialize sequence.
+ *
+ * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this is a reversed engineered driver based on captures from
+ * the I2C bus under Windows. This chip is very similar to the saa7134,
+ * though. Unfortunately, this driver is currently only working for NTSC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv.h>
+#include "compat.h"
+
+MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
+MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+module_param(debug, int, 0644);
+#else
+MODULE_PARM(debug, "i");
+#endif
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static unsigned short normal_i2c[] = { 0x42 >> 1, I2C_CLIENT_END };
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+#endif
+
+I2C_CLIENT_INSMOD;
+#endif
+
+struct saa717x_state {
+ v4l2_std_id std;
+ int input;
+ int enable;
+ int radio;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+ int playback;
+ int audio;
+ int tuner_audio_mode;
+ int audio_main_mute;
+ int audio_main_vol_r;
+ int audio_main_vol_l;
+ u16 audio_main_bass;
+ u16 audio_main_treble;
+ u16 audio_main_volume;
+ u16 audio_main_balance;
+ int audio_input;
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* for audio mode */
+#define TUNER_AUDIO_MONO 0 /* LL */
+#define TUNER_AUDIO_STEREO 1 /* LR */
+#define TUNER_AUDIO_LANG1 2 /* LL */
+#define TUNER_AUDIO_LANG2 3 /* RR */
+
+#define SAA717X_NTSC_WIDTH (704)
+#define SAA717X_NTSC_HEIGHT (480)
+
+/* ----------------------------------------------------------------------- */
+
+static int saa717x_write(struct i2c_client *client, u32 reg, u32 value)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
+ unsigned char mm1[6];
+ struct i2c_msg msg;
+
+ msg.flags = 0;
+ msg.addr = client->addr;
+ mm1[0] = (reg >> 8) & 0xff;
+ mm1[1] = reg & 0xff;
+
+ if (fw_addr) {
+ mm1[4] = (value >> 16) & 0xff;
+ mm1[3] = (value >> 8) & 0xff;
+ mm1[2] = value & 0xff;
+ } else {
+ mm1[2] = value & 0xff;
+ }
+ msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
+ msg.buf = mm1;
+ v4l_dbg(2, debug, client, "wrote: reg 0x%03x=%08x\n", reg, value);
+ return i2c_transfer(adap, &msg, 1) == 1;
+}
+
+static void saa717x_write_regs(struct i2c_client *client, u32 *data)
+{
+ while (data[0] || data[1]) {
+ saa717x_write(client, data[0], data[1]);
+ data += 2;
+ }
+}
+
+static u32 saa717x_read(struct i2c_client *client, u32 reg)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
+ unsigned char mm1[2];
+ unsigned char mm2[4] = { 0, 0, 0, 0 };
+ struct i2c_msg msgs[2];
+ u32 value;
+
+ msgs[0].flags = 0;
+ msgs[1].flags = I2C_M_RD;
+ msgs[0].addr = msgs[1].addr = client->addr;
+ mm1[0] = (reg >> 8) & 0xff;
+ mm1[1] = reg & 0xff;
+ msgs[0].len = 2;
+ msgs[0].buf = mm1;
+ msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
+ msgs[1].buf = mm2;
+ i2c_transfer(adap, msgs, 2);
+
+ if (fw_addr)
+ value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
+ else
+ value = mm2[0] & 0xff;
+
+ v4l_dbg(2, debug, client, "read: reg 0x%03x=0x%08x\n", reg, value);
+ return value;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static u32 reg_init_initialize[] =
+{
+ /* from linux driver */
+ 0x101, 0x008, /* Increment delay */
+
+ 0x103, 0x000, /* Analog input control 2 */
+ 0x104, 0x090, /* Analog input control 3 */
+ 0x105, 0x090, /* Analog input control 4 */
+ 0x106, 0x0eb, /* Horizontal sync start */
+ 0x107, 0x0e0, /* Horizontal sync stop */
+ 0x109, 0x055, /* Luminance control */
+
+ 0x10f, 0x02a, /* Chroma gain control */
+ 0x110, 0x000, /* Chroma control 2 */
+
+ 0x114, 0x045, /* analog/ADC */
+
+ 0x118, 0x040, /* RAW data gain */
+ 0x119, 0x080, /* RAW data offset */
+
+ 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
+ 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
+ 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
+ 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
+
+ 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
+
+ 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
+ 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
+
+ 0x064, 0x080, /* Lumina brightness TASK A */
+ 0x065, 0x040, /* Luminance contrast TASK A */
+ 0x066, 0x040, /* Chroma saturation TASK A */
+ /* 067H: Reserved */
+ 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
+ 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
+ 0x06a, 0x000, /* VBI phase offset TASK A */
+
+ 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
+ 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
+
+ 0x072, 0x000, /* Vertical filter mode TASK A */
+
+ 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
+ 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
+ 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
+ 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
+
+ 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
+
+ 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
+ 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
+
+ 0x0a4, 0x080, /* Lumina brightness TASK B */
+ 0x0a5, 0x040, /* Luminance contrast TASK B */
+ 0x0a6, 0x040, /* Chroma saturation TASK B */
+ /* 0A7H reserved */
+ 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
+ 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
+ 0x0aa, 0x000, /* VBI phase offset TASK B */
+
+ 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
+ 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
+
+ 0x0b2, 0x000, /* Vertical filter mode TASK B */
+
+ 0x00c, 0x000, /* Start point GREEN path */
+ 0x00d, 0x000, /* Start point BLUE path */
+ 0x00e, 0x000, /* Start point RED path */
+
+ 0x010, 0x010, /* GREEN path gamma curve --- */
+ 0x011, 0x020,
+ 0x012, 0x030,
+ 0x013, 0x040,
+ 0x014, 0x050,
+ 0x015, 0x060,
+ 0x016, 0x070,
+ 0x017, 0x080,
+ 0x018, 0x090,
+ 0x019, 0x0a0,
+ 0x01a, 0x0b0,
+ 0x01b, 0x0c0,
+ 0x01c, 0x0d0,
+ 0x01d, 0x0e0,
+ 0x01e, 0x0f0,
+ 0x01f, 0x0ff, /* --- GREEN path gamma curve */
+
+ 0x020, 0x010, /* BLUE path gamma curve --- */
+ 0x021, 0x020,
+ 0x022, 0x030,
+ 0x023, 0x040,
+ 0x024, 0x050,
+ 0x025, 0x060,
+ 0x026, 0x070,
+ 0x027, 0x080,
+ 0x028, 0x090,
+ 0x029, 0x0a0,
+ 0x02a, 0x0b0,
+ 0x02b, 0x0c0,
+ 0x02c, 0x0d0,
+ 0x02d, 0x0e0,
+ 0x02e, 0x0f0,
+ 0x02f, 0x0ff, /* --- BLUE path gamma curve */
+
+ 0x030, 0x010, /* RED path gamma curve --- */
+ 0x031, 0x020,
+ 0x032, 0x030,
+ 0x033, 0x040,
+ 0x034, 0x050,
+ 0x035, 0x060,
+ 0x036, 0x070,
+ 0x037, 0x080,
+ 0x038, 0x090,
+ 0x039, 0x0a0,
+ 0x03a, 0x0b0,
+ 0x03b, 0x0c0,
+ 0x03c, 0x0d0,
+ 0x03d, 0x0e0,
+ 0x03e, 0x0f0,
+ 0x03f, 0x0ff, /* --- RED path gamma curve */
+
+ 0x109, 0x085, /* Luminance control */
+
+ /**** from app start ****/
+ 0x584, 0x000, /* AGC gain control */
+ 0x585, 0x000, /* Program count */
+ 0x586, 0x003, /* Status reset */
+ 0x588, 0x0ff, /* Number of audio samples (L) */
+ 0x589, 0x00f, /* Number of audio samples (M) */
+ 0x58a, 0x000, /* Number of audio samples (H) */
+ 0x58b, 0x000, /* Audio select */
+ 0x58c, 0x010, /* Audio channel assign1 */
+ 0x58d, 0x032, /* Audio channel assign2 */
+ 0x58e, 0x054, /* Audio channel assign3 */
+ 0x58f, 0x023, /* Audio format */
+ 0x590, 0x000, /* SIF control */
+
+ 0x595, 0x000, /* ?? */
+ 0x596, 0x000, /* ?? */
+ 0x597, 0x000, /* ?? */
+
+ 0x464, 0x00, /* Digital input crossbar1 */
+
+ 0x46c, 0xbbbb10, /* Digital output selection1-3 */
+ 0x470, 0x101010, /* Digital output selection4-6 */
+
+ 0x478, 0x00, /* Sound feature control */
+
+ 0x474, 0x18, /* Softmute control */
+
+ 0x454, 0x0425b9, /* Sound Easy programming(reset) */
+ 0x454, 0x042539, /* Sound Easy programming(reset) */
+
+
+ /**** common setting( of DVD play, including scaler commands) ****/
+ 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
+
+ 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
+
+ 0x108, 0x0f8, /* Sync control */
+ 0x2a9, 0x0fd, /* ??? */
+ 0x102, 0x089, /* select video input "mode 9" */
+ 0x111, 0x000, /* Mode/delay control */
+
+ 0x10e, 0x00a, /* Chroma control 1 */
+
+ 0x594, 0x002, /* SIF, analog I/O select */
+
+ 0x454, 0x0425b9, /* Sound */
+ 0x454, 0x042539,
+
+ 0x111, 0x000,
+ 0x10e, 0x00a,
+ 0x464, 0x000,
+ 0x300, 0x000,
+ 0x301, 0x006,
+ 0x302, 0x000,
+ 0x303, 0x006,
+ 0x308, 0x040,
+ 0x309, 0x000,
+ 0x30a, 0x000,
+ 0x30b, 0x000,
+ 0x000, 0x002,
+ 0x001, 0x000,
+ 0x002, 0x000,
+ 0x003, 0x000,
+ 0x004, 0x033,
+ 0x040, 0x01d,
+ 0x041, 0x001,
+ 0x042, 0x004,
+ 0x043, 0x000,
+ 0x080, 0x01e,
+ 0x081, 0x001,
+ 0x082, 0x004,
+ 0x083, 0x000,
+ 0x190, 0x018,
+ 0x115, 0x000,
+ 0x116, 0x012,
+ 0x117, 0x018,
+ 0x04a, 0x011,
+ 0x08a, 0x011,
+ 0x04b, 0x000,
+ 0x08b, 0x000,
+ 0x048, 0x000,
+ 0x088, 0x000,
+ 0x04e, 0x012,
+ 0x08e, 0x012,
+ 0x058, 0x012,
+ 0x098, 0x012,
+ 0x059, 0x000,
+ 0x099, 0x000,
+ 0x05a, 0x003,
+ 0x09a, 0x003,
+ 0x05b, 0x001,
+ 0x09b, 0x001,
+ 0x054, 0x008,
+ 0x094, 0x008,
+ 0x055, 0x000,
+ 0x095, 0x000,
+ 0x056, 0x0c7,
+ 0x096, 0x0c7,
+ 0x057, 0x002,
+ 0x097, 0x002,
+ 0x0ff, 0x0ff,
+ 0x060, 0x001,
+ 0x0a0, 0x001,
+ 0x061, 0x000,
+ 0x0a1, 0x000,
+ 0x062, 0x000,
+ 0x0a2, 0x000,
+ 0x063, 0x000,
+ 0x0a3, 0x000,
+ 0x070, 0x000,
+ 0x0b0, 0x000,
+ 0x071, 0x004,
+ 0x0b1, 0x004,
+ 0x06c, 0x0e9,
+ 0x0ac, 0x0e9,
+ 0x06d, 0x003,
+ 0x0ad, 0x003,
+ 0x05c, 0x0d0,
+ 0x09c, 0x0d0,
+ 0x05d, 0x002,
+ 0x09d, 0x002,
+ 0x05e, 0x0f2,
+ 0x09e, 0x0f2,
+ 0x05f, 0x000,
+ 0x09f, 0x000,
+ 0x074, 0x000,
+ 0x0b4, 0x000,
+ 0x075, 0x000,
+ 0x0b5, 0x000,
+ 0x076, 0x000,
+ 0x0b6, 0x000,
+ 0x077, 0x000,
+ 0x0b7, 0x000,
+ 0x195, 0x008,
+ 0x0ff, 0x0ff,
+ 0x108, 0x0f8,
+ 0x111, 0x000,
+ 0x10e, 0x00a,
+ 0x2a9, 0x0fd,
+ 0x464, 0x001,
+ 0x454, 0x042135,
+ 0x598, 0x0e7,
+ 0x599, 0x07d,
+ 0x59a, 0x018,
+ 0x59c, 0x066,
+ 0x59d, 0x090,
+ 0x59e, 0x001,
+ 0x584, 0x000,
+ 0x585, 0x000,
+ 0x586, 0x003,
+ 0x588, 0x0ff,
+ 0x589, 0x00f,
+ 0x58a, 0x000,
+ 0x58b, 0x000,
+ 0x58c, 0x010,
+ 0x58d, 0x032,
+ 0x58e, 0x054,
+ 0x58f, 0x023,
+ 0x590, 0x000,
+ 0x595, 0x000,
+ 0x596, 0x000,
+ 0x597, 0x000,
+ 0x464, 0x000,
+ 0x46c, 0xbbbb10,
+ 0x470, 0x101010,
+
+
+ 0x478, 0x000,
+ 0x474, 0x018,
+ 0x454, 0x042135,
+ 0x598, 0x0e7,
+ 0x599, 0x07d,
+ 0x59a, 0x018,
+ 0x59c, 0x066,
+ 0x59d, 0x090,
+ 0x59e, 0x001,
+ 0x584, 0x000,
+ 0x585, 0x000,
+ 0x586, 0x003,
+ 0x588, 0x0ff,
+ 0x589, 0x00f,
+ 0x58a, 0x000,
+ 0x58b, 0x000,
+ 0x58c, 0x010,
+ 0x58d, 0x032,
+ 0x58e, 0x054,
+ 0x58f, 0x023,
+ 0x590, 0x000,
+ 0x595, 0x000,
+ 0x596, 0x000,
+ 0x597, 0x000,
+ 0x464, 0x000,
+ 0x46c, 0xbbbb10,
+ 0x470, 0x101010,
+
+ 0x478, 0x000,
+ 0x474, 0x018,
+ 0x454, 0x042135,
+ 0x598, 0x0e7,
+ 0x599, 0x07d,
+ 0x59a, 0x018,
+ 0x59c, 0x066,
+ 0x59d, 0x090,
+ 0x59e, 0x001,
+ 0x584, 0x000,
+ 0x585, 0x000,
+ 0x586, 0x003,
+ 0x588, 0x0ff,
+ 0x589, 0x00f,
+ 0x58a, 0x000,
+ 0x58b, 0x000,
+ 0x58c, 0x010,
+ 0x58d, 0x032,
+ 0x58e, 0x054,
+ 0x58f, 0x023,
+ 0x590, 0x000,
+ 0x595, 0x000,
+ 0x596, 0x000,
+ 0x597, 0x000,
+ 0x464, 0x000,
+ 0x46c, 0xbbbb10,
+ 0x470, 0x101010,
+ 0x478, 0x000,
+ 0x474, 0x018,
+ 0x454, 0x042135,
+ 0x193, 0x000,
+ 0x300, 0x000,
+ 0x301, 0x006,
+ 0x302, 0x000,
+ 0x303, 0x006,
+ 0x308, 0x040,
+ 0x309, 0x000,
+ 0x30a, 0x000,
+ 0x30b, 0x000,
+ 0x000, 0x002,
+ 0x001, 0x000,
+ 0x002, 0x000,
+ 0x003, 0x000,
+ 0x004, 0x033,
+ 0x040, 0x01d,
+ 0x041, 0x001,
+ 0x042, 0x004,
+ 0x043, 0x000,
+ 0x080, 0x01e,
+ 0x081, 0x001,
+ 0x082, 0x004,
+ 0x083, 0x000,
+ 0x190, 0x018,
+ 0x115, 0x000,
+ 0x116, 0x012,
+ 0x117, 0x018,
+ 0x04a, 0x011,
+ 0x08a, 0x011,
+ 0x04b, 0x000,
+ 0x08b, 0x000,
+ 0x048, 0x000,
+ 0x088, 0x000,
+ 0x04e, 0x012,
+ 0x08e, 0x012,
+ 0x058, 0x012,
+ 0x098, 0x012,
+ 0x059, 0x000,
+ 0x099, 0x000,
+ 0x05a, 0x003,
+ 0x09a, 0x003,
+ 0x05b, 0x001,
+ 0x09b, 0x001,
+ 0x054, 0x008,
+ 0x094, 0x008,
+ 0x055, 0x000,
+ 0x095, 0x000,
+ 0x056, 0x0c7,
+ 0x096, 0x0c7,
+ 0x057, 0x002,
+ 0x097, 0x002,
+ 0x060, 0x001,
+ 0x0a0, 0x001,
+ 0x061, 0x000,
+ 0x0a1, 0x000,
+ 0x062, 0x000,
+ 0x0a2, 0x000,
+ 0x063, 0x000,
+ 0x0a3, 0x000,
+ 0x070, 0x000,
+ 0x0b0, 0x000,
+ 0x071, 0x004,
+ 0x0b1, 0x004,
+ 0x06c, 0x0e9,
+ 0x0ac, 0x0e9,
+ 0x06d, 0x003,
+ 0x0ad, 0x003,
+ 0x05c, 0x0d0,
+ 0x09c, 0x0d0,
+ 0x05d, 0x002,
+ 0x09d, 0x002,
+ 0x05e, 0x0f2,
+ 0x09e, 0x0f2,
+ 0x05f, 0x000,
+ 0x09f, 0x000,
+ 0x074, 0x000,
+ 0x0b4, 0x000,
+ 0x075, 0x000,
+ 0x0b5, 0x000,
+ 0x076, 0x000,
+ 0x0b6, 0x000,
+ 0x077, 0x000,
+ 0x0b7, 0x000,
+ 0x195, 0x008,
+ 0x598, 0x0e7,
+ 0x599, 0x07d,
+ 0x59a, 0x018,
+ 0x59c, 0x066,
+ 0x59d, 0x090,
+ 0x59e, 0x001,
+ 0x584, 0x000,
+ 0x585, 0x000,
+ 0x586, 0x003,
+ 0x588, 0x0ff,
+ 0x589, 0x00f,
+ 0x58a, 0x000,
+ 0x58b, 0x000,
+ 0x58c, 0x010,
+ 0x58d, 0x032,
+ 0x58e, 0x054,
+ 0x58f, 0x023,
+ 0x590, 0x000,
+ 0x595, 0x000,
+ 0x596, 0x000,
+ 0x597, 0x000,
+ 0x464, 0x000,
+ 0x46c, 0xbbbb10,
+ 0x470, 0x101010,
+ 0x478, 0x000,
+ 0x474, 0x018,
+ 0x454, 0x042135,
+ 0x193, 0x0a6,
+ 0x108, 0x0f8,
+ 0x042, 0x003,
+ 0x082, 0x003,
+ 0x454, 0x0425b9,
+ 0x454, 0x042539,
+ 0x193, 0x000,
+ 0x193, 0x0a6,
+ 0x464, 0x000,
+
+ 0, 0
+};
+
+/* Tuner */
+static u32 reg_init_tuner_input[] = {
+ 0x108, 0x0f8, /* Sync control */
+ 0x111, 0x000, /* Mode/delay control */
+ 0x10e, 0x00a, /* Chroma control 1 */
+ 0, 0
+};
+
+/* Composite */
+static u32 reg_init_composite_input[] = {
+ 0x108, 0x0e8, /* Sync control */
+ 0x111, 0x000, /* Mode/delay control */
+ 0x10e, 0x04a, /* Chroma control 1 */
+ 0, 0
+};
+
+/* S-Video */
+static u32 reg_init_svideo_input[] = {
+ 0x108, 0x0e8, /* Sync control */
+ 0x111, 0x000, /* Mode/delay control */
+ 0x10e, 0x04a, /* Chroma control 1 */
+ 0, 0
+};
+
+static u32 reg_set_audio_template[4][2] =
+{
+ { /* for MONO
+ tadachi 6/29 DMA audio output select?
+ Register 0x46c
+ 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
+ 0: MAIN left, 1: MAIN right
+ 2: AUX1 left, 3: AUX1 right
+ 4: AUX2 left, 5: AUX2 right
+ 6: DPL left, 7: DPL right
+ 8: DPL center, 9: DPL surround
+ A: monitor output, B: digital sense */
+ 0xbbbb00,
+
+ /* tadachi 6/29 DAC and I2S output select?
+ Register 0x470
+ 7-4:DAC right ch. 3-0:DAC left ch.
+ I2S1 right,left I2S2 right,left */
+ 0x00,
+ },
+ { /* for STEREO */
+ 0xbbbb10, 0x101010,
+ },
+ { /* for LANG1 */
+ 0xbbbb00, 0x00,
+ },
+ { /* for LANG2/SAP */
+ 0xbbbb11, 0x111111,
+ }
+};
+
+
+/* Get detected audio flags (from saa7134 driver) */
+static void get_inf_dev_status(struct i2c_client *client,
+ int *dual_flag, int *stereo_flag)
+{
+ u32 reg_data3;
+
+ static char *stdres[0x20] = {
+ [0x00] = "no standard detected",
+ [0x01] = "B/G (in progress)",
+ [0x02] = "D/K (in progress)",
+ [0x03] = "M (in progress)",
+
+ [0x04] = "B/G A2",
+ [0x05] = "B/G NICAM",
+ [0x06] = "D/K A2 (1)",
+ [0x07] = "D/K A2 (2)",
+ [0x08] = "D/K A2 (3)",
+ [0x09] = "D/K NICAM",
+ [0x0a] = "L NICAM",
+ [0x0b] = "I NICAM",
+
+ [0x0c] = "M Korea",
+ [0x0d] = "M BTSC ",
+ [0x0e] = "M EIAJ",
+
+ [0x0f] = "FM radio / IF 10.7 / 50 deemp",
+ [0x10] = "FM radio / IF 10.7 / 75 deemp",
+ [0x11] = "FM radio / IF sel / 50 deemp",
+ [0x12] = "FM radio / IF sel / 75 deemp",
+
+ [0x13 ... 0x1e] = "unknown",
+ [0x1f] = "??? [in progress]",
+ };
+
+
+ *dual_flag = *stereo_flag = 0;
+
+ /* (demdec status: 0x528) */
+
+ /* read current status */
+ reg_data3 = saa717x_read(client, 0x0528);
+
+ v4l_dbg(1, debug, client, "tvaudio thread status: 0x%x [%s%s%s]\n",
+ reg_data3, stdres[reg_data3 & 0x1f],
+ (reg_data3 & 0x000020) ? ",stereo" : "",
+ (reg_data3 & 0x000040) ? ",dual" : "");
+ v4l_dbg(1, debug, client, "detailed status: "
+ "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
+ (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
+ (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
+ (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
+ (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
+
+ (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
+ (reg_data3 & 0x001000) ? " SAP carrier " : "",
+ (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
+ (reg_data3 & 0x004000) ? " SAP noise mute " : "",
+ (reg_data3 & 0x008000) ? " VDSP " : "",
+
+ (reg_data3 & 0x010000) ? " NICST " : "",
+ (reg_data3 & 0x020000) ? " NICDU " : "",
+ (reg_data3 & 0x040000) ? " NICAM muted " : "",
+ (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
+
+ (reg_data3 & 0x100000) ? " init done " : "");
+
+ if (reg_data3 & 0x000220) {
+ v4l_dbg(1, debug, client, "ST!!!\n");
+ *stereo_flag = 1;
+ }
+
+ if (reg_data3 & 0x000140) {
+ v4l_dbg(1, debug, client, "DUAL!!!\n");
+ *dual_flag = 1;
+ }
+}
+
+/* regs write to set audio mode */
+static void set_audio_mode(struct i2c_client *client, int audio_mode)
+{
+ v4l_dbg(1, debug, client, "writing registers to set audio mode by set %d\n",
+ audio_mode);
+
+ saa717x_write(client, 0x46c, reg_set_audio_template[audio_mode][0]);
+ saa717x_write(client, 0x470, reg_set_audio_template[audio_mode][1]);
+}
+
+/* write regs to video output level (bright,contrast,hue,sat) */
+static void set_video_output_level_regs(struct i2c_client *client,
+ struct saa717x_state *decoder)
+{
+ /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
+ saa717x_write(client, 0x10a, decoder->bright);
+
+ /* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
+ 0h (luminance off) 40: i2c dump
+ c0h (-1.0 inverse chrominance)
+ 80h (-2.0 inverse chrominance) */
+ saa717x_write(client, 0x10b, decoder->contrast);
+
+ /* saturation? 7fh(max)-40h(ITU)-0h(color off)
+ c0h (-1.0 inverse chrominance)
+ 80h (-2.0 inverse chrominance) */
+ saa717x_write(client, 0x10c, decoder->sat);
+
+ /* color hue (phase) control
+ 7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
+ saa717x_write(client, 0x10d, decoder->hue);
+}
+
+/* write regs to set audio volume, bass and treble */
+static int set_audio_regs(struct i2c_client *client,
+ struct saa717x_state *decoder)
+{
+ u8 mute = 0xac; /* -84 dB */
+ u32 val;
+ unsigned int work_l, work_r;
+
+ /* set SIF analog I/O select */
+ saa717x_write(client, 0x0594, decoder->audio_input);
+ v4l_dbg(1, debug, client, "set audio input %d\n",
+ decoder->audio_input);
+
+ /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
+ work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
+ work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
+ decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
+ decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
+
+ /* set main volume */
+ /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */
+ /* def:0dB->6dB(MPG600GR) */
+ /* if mute is on, set mute */
+ if (decoder->audio_main_mute) {
+ val = mute | (mute << 8);
+ } else {
+ val = (u8)decoder->audio_main_vol_l |
+ ((u8)decoder->audio_main_vol_r << 8);
+ }
+
+ saa717x_write(client, 0x480, val);
+
+ /* bass and treble; go to another function */
+ /* set bass and treble */
+ val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
+ saa717x_write(client, 0x488, val);
+ return 0;
+}
+
+/********** scaling staff ***********/
+static void set_h_prescale(struct i2c_client *client,
+ int task, int prescale)
+{
+ static const struct {
+ int xpsc;
+ int xacl;
+ int xc2_1;
+ int xdcg;
+ int vpfy;
+ } vals[] = {
+ /* XPSC XACL XC2_1 XDCG VPFY */
+ { 1, 0, 0, 0, 0 },
+ { 2, 2, 1, 2, 2 },
+ { 3, 4, 1, 3, 2 },
+ { 4, 8, 1, 4, 2 },
+ { 5, 8, 1, 4, 2 },
+ { 6, 8, 1, 4, 3 },
+ { 7, 8, 1, 4, 3 },
+ { 8, 15, 0, 4, 3 },
+ { 9, 15, 0, 4, 3 },
+ { 10, 16, 1, 5, 3 },
+ };
+ static const int count = ARRAY_SIZE(vals);
+ int i, task_shift;
+
+ task_shift = task * 0x40;
+ for (i = 0; i < count; i++)
+ if (vals[i].xpsc == prescale)
+ break;
+ if (i == count)
+ return;
+
+ /* horizonal prescaling */
+ saa717x_write(client, 0x60 + task_shift, vals[i].xpsc);
+ /* accumulation length */
+ saa717x_write(client, 0x61 + task_shift, vals[i].xacl);
+ /* level control */
+ saa717x_write(client, 0x62 + task_shift,
+ (vals[i].xc2_1 << 3) | vals[i].xdcg);
+ /*FIR prefilter control */
+ saa717x_write(client, 0x63 + task_shift,
+ (vals[i].vpfy << 2) | vals[i].vpfy);
+}
+
+/********** scaling staff ***********/
+static void set_v_scale(struct i2c_client *client, int task, int yscale)
+{
+ int task_shift;
+
+ task_shift = task * 0x40;
+ /* Vertical scaling ratio (LOW) */
+ saa717x_write(client, 0x70 + task_shift, yscale & 0xff);
+ /* Vertical scaling ratio (HI) */
+ saa717x_write(client, 0x71 + task_shift, yscale >> 8);
+}
+
+static int saa717x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
+{
+ /* not yet implament, so saa717x_cfg_??hz_??_audio is not defined. */
+ return 0;
+}
+
+static int saa717x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct saa717x_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->bright = ctrl->value;
+ v4l_dbg(1, debug, client, "bright:%d\n", state->bright);
+ saa717x_write(client, 0x10a, state->bright);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->contrast = ctrl->value;
+ v4l_dbg(1, debug, client, "contrast:%d\n", state->contrast);
+ saa717x_write(client, 0x10b, state->contrast);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->sat = ctrl->value;
+ v4l_dbg(1, debug, client, "sat:%d\n", state->sat);
+ saa717x_write(client, 0x10c, state->sat);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ v4l_err(client, "invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->hue = ctrl->value;
+ v4l_dbg(1, debug, client, "hue:%d\n", state->hue);
+ saa717x_write(client, 0x10d, state->hue);
+ break;
+
+ case V4L2_CID_AUDIO_MUTE:
+ state->audio_main_mute = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ state->audio_main_volume = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ state->audio_main_balance = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ case V4L2_CID_AUDIO_TREBLE:
+ state->audio_main_treble = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ case V4L2_CID_AUDIO_BASS:
+ state->audio_main_bass = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int saa717x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct saa717x_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = state->bright;
+ break;
+
+ case V4L2_CID_CONTRAST:
+ ctrl->value = state->contrast;
+ break;
+
+ case V4L2_CID_SATURATION:
+ ctrl->value = state->sat;
+ break;
+
+ case V4L2_CID_HUE:
+ ctrl->value = state->hue;
+ break;
+
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = state->audio_main_mute;
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = state->audio_main_volume;
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = state->audio_main_balance;
+ break;
+
+ case V4L2_CID_AUDIO_TREBLE:
+ ctrl->value = state->audio_main_treble;
+ break;
+
+ case V4L2_CID_AUDIO_BASS:
+ ctrl->value = state->audio_main_bass;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct v4l2_queryctrl saa717x_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 58880,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Balance",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 32768,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_BASS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Bass",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 32768,
+ }, {
+ .id = V4L2_CID_AUDIO_TREBLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Treble",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 32768,
+ },
+};
+
+static int saa717x_set_video_input(struct i2c_client *client, struct saa717x_state *decoder, int inp)
+{
+ int is_tuner = inp & 0x80; /* tuner input flag */
+
+ inp &= 0x7f;
+
+ v4l_dbg(1, debug, client, "decoder set input (%d)\n", inp);
+ /* inputs from 0-9 are available*/
+ /* saa717x have mode0-mode9 but mode5 is reserved. */
+ if (inp < 0 || inp > 9 || inp == 5)
+ return -EINVAL;
+
+ if (decoder->input != inp) {
+ int input_line = inp;
+
+ decoder->input = input_line;
+ v4l_dbg(1, debug, client, "now setting %s input %d\n",
+ input_line >= 6 ? "S-Video" : "Composite",
+ input_line);
+
+ /* select mode */
+ saa717x_write(client, 0x102,
+ (saa717x_read(client, 0x102) & 0xf0) |
+ input_line);
+
+ /* bypass chrominance trap for modes 6..9 */
+ saa717x_write(client, 0x109,
+ (saa717x_read(client, 0x109) & 0x7f) |
+ (input_line < 6 ? 0x0 : 0x80));
+
+ /* change audio_mode */
+ if (is_tuner) {
+ /* tuner */
+ set_audio_mode(client, decoder->tuner_audio_mode);
+ } else {
+ /* Force to STEREO mode if Composite or
+ * S-Video were chosen */
+ set_audio_mode(client, TUNER_AUDIO_STEREO);
+ }
+ /* change initialize procedure (Composite/S-Video) */
+ if (is_tuner)
+ saa717x_write_regs(client, reg_init_tuner_input);
+ else if (input_line >= 6)
+ saa717x_write_regs(client, reg_init_svideo_input);
+ else
+ saa717x_write_regs(client, reg_init_composite_input);
+ }
+
+ return 0;
+}
+
+static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ struct saa717x_state *decoder = i2c_get_clientdata(client);
+
+ v4l_dbg(1, debug, client, "IOCTL: %08x\n", cmd);
+
+ switch (cmd) {
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return saa717x_set_audio_clock_freq(client, *(u32 *)arg);
+
+ case VIDIOC_G_CTRL:
+ return saa717x_get_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_S_CTRL:
+ return saa717x_set_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_QUERYCTRL: {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
+ if (qc->id && qc->id == saa717x_qctrl[i].id) {
+ memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_G_REGISTER: {
+ struct v4l2_register *reg = arg;
+
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = saa717x_read(client, reg->reg);
+ break;
+ }
+
+ case VIDIOC_DBG_S_REGISTER: {
+ struct v4l2_register *reg = arg;
+ u16 addr = reg->reg & 0xffff;
+ u8 val = reg->val & 0xff;
+
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa717x_write(client, addr, val);
+ break;
+ }
+#endif
+
+ case VIDIOC_S_FMT: {
+ struct v4l2_format *fmt = (struct v4l2_format *)arg;
+ struct v4l2_pix_format *pix;
+ int prescale, h_scale, v_scale;
+
+ pix = &fmt->fmt.pix;
+ v4l_dbg(1, debug, client, "decoder set size\n");
+
+ /* FIXME need better bounds checking here */
+ if (pix->width < 1 || pix->width > 1440)
+ return -EINVAL;
+ if (pix->height < 1 || pix->height > 960)
+ return -EINVAL;
+
+ /* scaling setting */
+ /* NTSC and interlace only */
+ prescale = SAA717X_NTSC_WIDTH / pix->width;
+ if (prescale == 0)
+ prescale = 1;
+ h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
+ /* interlace */
+ v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
+
+ /* Horizontal prescaling etc */
+ set_h_prescale(client, 0, prescale);
+ set_h_prescale(client, 1, prescale);
+
+ /* Horizontal scaling increment */
+ /* TASK A */
+ saa717x_write(client, 0x6C, (u8)(h_scale & 0xFF));
+ saa717x_write(client, 0x6D, (u8)((h_scale >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(client, 0xAC, (u8)(h_scale & 0xFF));
+ saa717x_write(client, 0xAD, (u8)((h_scale >> 8) & 0xFF));
+
+ /* Vertical prescaling etc */
+ set_v_scale(client, 0, v_scale);
+ set_v_scale(client, 1, v_scale);
+
+ /* set video output size */
+ /* video number of pixels at output */
+ /* TASK A */
+ saa717x_write(client, 0x5C, (u8)(pix->width & 0xFF));
+ saa717x_write(client, 0x5D, (u8)((pix->width >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(client, 0x9C, (u8)(pix->width & 0xFF));
+ saa717x_write(client, 0x9D, (u8)((pix->width >> 8) & 0xFF));
+
+ /* video number of lines at output */
+ /* TASK A */
+ saa717x_write(client, 0x5E, (u8)(pix->height & 0xFF));
+ saa717x_write(client, 0x5F, (u8)((pix->height >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(client, 0x9E, (u8)(pix->height & 0xFF));
+ saa717x_write(client, 0x9F, (u8)((pix->height >> 8) & 0xFF));
+ break;
+ }
+
+ case AUDC_SET_RADIO:
+ decoder->radio = 1;
+ break;
+
+ case VIDIOC_S_STD: {
+ v4l2_std_id std = *(v4l2_std_id *) arg;
+
+ v4l_dbg(1, debug, client, "decoder set norm ");
+ v4l_dbg(1, debug, client, "(not yet implementd)\n");
+
+ decoder->radio = 0;
+ decoder->std = std;
+ break;
+ }
+
+ case VIDIOC_INT_G_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
+
+ route->input = decoder->audio_input;
+ route->output = 0;
+ break;
+ }
+
+ case VIDIOC_INT_S_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
+
+ if (route->input < 3) { /* FIXME! --tadachi */
+ decoder->audio_input = route->input;
+ v4l_dbg(1, debug, client,
+ "set decoder audio input to %d\n",
+ decoder->audio_input);
+ set_audio_regs(client, decoder);
+ break;
+ }
+ return -ERANGE;
+ }
+
+ case VIDIOC_INT_S_VIDEO_ROUTING: {
+ struct v4l2_routing *route = arg;
+ int inp = route->input;
+
+ return saa717x_set_video_input(client, decoder, inp);
+ }
+
+ case VIDIOC_STREAMON: {
+ v4l_dbg(1, debug, client, "decoder enable output\n");
+ decoder->enable = 1;
+ saa717x_write(client, 0x193, 0xa6);
+ break;
+ }
+
+ case VIDIOC_STREAMOFF: {
+ v4l_dbg(1, debug, client, "decoder disable output\n");
+ decoder->enable = 0;
+ saa717x_write(client, 0x193, 0x26); /* right? FIXME!--tadachi */
+ break;
+ }
+
+ /* change audio mode */
+ case VIDIOC_S_TUNER: {
+ struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+ int audio_mode;
+ char *mes[4] = {
+ "MONO", "STEREO", "LANG1", "LANG2/SAP"
+ };
+
+ audio_mode = V4L2_TUNER_MODE_STEREO;
+
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ audio_mode = TUNER_AUDIO_MONO;
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ audio_mode = TUNER_AUDIO_STEREO;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ audio_mode = TUNER_AUDIO_LANG2;
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ audio_mode = TUNER_AUDIO_LANG1;
+ break;
+ }
+
+ v4l_dbg(1, debug, client, "change audio mode to %s\n",
+ mes[audio_mode]);
+ decoder->tuner_audio_mode = audio_mode;
+ /* The registers are not changed here. */
+ /* See DECODER_ENABLE_OUTPUT section. */
+ set_audio_mode(client, decoder->tuner_audio_mode);
+ break;
+ }
+
+ case VIDIOC_G_TUNER: {
+ struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+ int dual_f, stereo_f;
+
+ if (decoder->radio)
+ break;
+ get_inf_dev_status(client, &dual_f, &stereo_f);
+
+ v4l_dbg(1, debug, client, "DETECT==st:%d dual:%d\n",
+ stereo_f, dual_f);
+
+ /* mono */
+ if ((dual_f == 0) && (stereo_f == 0)) {
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v4l_dbg(1, debug, client, "DETECT==MONO\n");
+ }
+
+ /* stereo */
+ if (stereo_f == 1) {
+ if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
+ vt->audmode == V4L2_TUNER_MODE_LANG1) {
+ vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ v4l_dbg(1, debug, client, "DETECT==ST(ST)\n");
+ } else {
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v4l_dbg(1, debug, client, "DETECT==ST(MONO)\n");
+ }
+ }
+
+ /* dual */
+ if (dual_f == 1) {
+ if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
+ vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
+ v4l_dbg(1, debug, client, "DETECT==DUAL1\n");
+ } else {
+ vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
+ v4l_dbg(1, debug, client, "DETECT==DUAL2\n");
+ }
+ }
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ /* not yet implemented */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+
+/* i2c implementation */
+
+/* ----------------------------------------------------------------------- */
+static int saa717x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct saa717x_state *decoder;
+ u8 id = 0;
+ char *p = "";
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+ snprintf(client->name, sizeof(client->name) - 1, "saa717x");
+#endif
+ if (saa717x_write(client, 0x5a4, 0xfe) &&
+ saa717x_write(client, 0x5a5, 0x0f) &&
+ saa717x_write(client, 0x5a6, 0x00) &&
+ saa717x_write(client, 0x5a7, 0x01))
+ id = saa717x_read(client, 0x5a0);
+ if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
+ v4l_dbg(1, debug, client, "saa717x not found (id=%02x)\n", id);
+ return -ENODEV;
+ }
+ if (id == 0xc2)
+ p = "saa7173";
+ else if (id == 0x32)
+ p = "saa7174A";
+ else if (id == 0x6c)
+ p = "saa7174HL";
+ else
+ p = "saa7171";
+ v4l_info(client, "%s found @ 0x%x (%s)\n", p,
+ client->addr << 1, client->adapter->name);
+
+ decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
+ i2c_set_clientdata(client, decoder);
+
+ if (decoder == NULL)
+ return -ENOMEM;
+ decoder->std = V4L2_STD_NTSC;
+ decoder->input = -1;
+ decoder->enable = 1;
+
+ /* tune these parameters */
+ decoder->bright = 0x80;
+ decoder->contrast = 0x44;
+ decoder->sat = 0x40;
+ decoder->hue = 0x00;
+
+ /* FIXME!! */
+ decoder->playback = 0; /* initially capture mode used */
+ decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
+
+ decoder->audio_input = 2; /* FIXME!! */
+
+ decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
+ /* set volume, bass and treble */
+ decoder->audio_main_vol_l = 6;
+ decoder->audio_main_vol_r = 6;
+ decoder->audio_main_bass = 0;
+ decoder->audio_main_treble = 0;
+ decoder->audio_main_mute = 0;
+ decoder->audio_main_balance = 32768;
+ /* normalize (24 to -40 (not -84) -> 65535 to 0) */
+ decoder->audio_main_volume =
+ (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
+
+ v4l_dbg(1, debug, client, "writing init values\n");
+
+ /* FIXME!! */
+ saa717x_write_regs(client, reg_init_initialize);
+ set_video_output_level_regs(client, decoder);
+ /* set bass,treble to 0db 20041101 K.Ohta */
+ decoder->audio_main_bass = 0;
+ decoder->audio_main_treble = 0;
+ set_audio_regs(client, decoder);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2*HZ);
+ return 0;
+}
+
+static int saa717x_remove(struct i2c_client *client)
+{
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id saa717x_id[] = {
+ { "saa717x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, saa717x_id);
+
+#endif
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa717x",
+ .driverid = I2C_DRIVERID_SAA717X,
+ .command = saa717x_command,
+ .probe = saa717x_probe,
+ .remove = saa717x_remove,
+#ifdef I2C_CLASS_TV_ANALOG
+ .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = saa717x_id,
+#endif
+};
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
+EXPORT_NO_SYMBOLS;
+#endif
diff --git a/linux/drivers/media/video/saa7185.c b/linux/drivers/media/video/saa7185.c
index 2ac144d9a..7a6c9c1fb 100644
--- a/linux/drivers/media/video/saa7185.c
+++ b/linux/drivers/media/video/saa7185.c
@@ -404,7 +404,7 @@ saa7185_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/se401.c b/linux/drivers/media/video/se401.c
index 1bc4b3a3f..c82bfddde 100644
--- a/linux/drivers/media/video/se401.c
+++ b/linux/drivers/media/video/se401.c
@@ -304,10 +304,10 @@ static void se401_button_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __func__, urb->status);
goto exit;
}
@@ -319,7 +319,7 @@ exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __func__, status);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
diff --git a/linux/drivers/media/video/sn9c102/sn9c102.h b/linux/drivers/media/video/sn9c102/sn9c102.h
index e845e2dea..c6e41428d 100644
--- a/linux/drivers/media/video/sn9c102/sn9c102.h
+++ b/linux/drivers/media/video/sn9c102/sn9c102.h
@@ -183,7 +183,7 @@ do { \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -198,7 +198,7 @@ do { \
pr_info("sn9c102: " fmt "\n", ## args); \
else if ((level) == 3) \
pr_debug("sn9c102: [%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
} while (0)
#else
@@ -209,7 +209,7 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
__LINE__ , ## args)
#undef PDBGG
diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c
index b1a7e36d2..6747c4d7c 100644
--- a/linux/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c
@@ -34,7 +34,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c
index 1e9215788..208ed5278 100644
--- a/linux/drivers/media/video/soc_camera.c
+++ b/linux/drivers/media/video/soc_camera.c
@@ -44,7 +44,7 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
return NULL;
}
-static int soc_camera_try_fmt_cap(struct file *file, void *priv,
+static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
@@ -137,15 +137,13 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s: %d\n", __FUNCTION__, p->memory);
+ dev_dbg(&icd->dev, "%s: %d\n", __func__, p->memory);
ret = videobuf_reqbufs(&icf->vb_vidq, p);
if (ret < 0)
return ret;
return ici->ops->reqbufs(icf, p);
-
- return ret;
}
static int soc_camera_querybuf(struct file *file, void *priv,
@@ -344,7 +342,7 @@ static struct file_operations soc_camera_fops = {
};
-static int soc_camera_s_fmt_cap(struct file *file, void *priv,
+static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
@@ -364,7 +362,7 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
/* buswidth may be further adjusted by the ici */
icd->buswidth = data_fmt->depth;
- ret = soc_camera_try_fmt_cap(file, icf, f);
+ ret = soc_camera_try_fmt_vid_cap(file, icf, f);
if (ret < 0)
return ret;
@@ -391,7 +389,7 @@ static int soc_camera_s_fmt_cap(struct file *file, void *priv,
return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
}
-static int soc_camera_enum_fmt_cap(struct file *file, void *priv,
+static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct soc_camera_file *icf = file->private_data;
@@ -410,7 +408,7 @@ static int soc_camera_enum_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int soc_camera_g_fmt_cap(struct file *file, void *priv,
+static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct soc_camera_file *icf = file->private_data;
@@ -453,7 +451,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s\n", __func__);
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -472,7 +470,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
WARN_ON(priv != file->private_data);
- dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s\n", __func__);
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -937,15 +935,15 @@ int soc_camera_video_start(struct soc_camera_device *icd)
vdev->minor = -1;
vdev->tvnorms = V4L2_STD_UNKNOWN,
vdev->vidioc_querycap = soc_camera_querycap;
- vdev->vidioc_g_fmt_cap = soc_camera_g_fmt_cap;
- vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap;
- vdev->vidioc_s_fmt_cap = soc_camera_s_fmt_cap;
+ vdev->vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap;
+ vdev->vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap;
+ vdev->vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap;
vdev->vidioc_enum_input = soc_camera_enum_input;
vdev->vidioc_g_input = soc_camera_g_input;
vdev->vidioc_s_input = soc_camera_s_input;
vdev->vidioc_s_std = soc_camera_s_std;
vdev->vidioc_reqbufs = soc_camera_reqbufs;
- vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap;
+ vdev->vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap;
vdev->vidioc_querybuf = soc_camera_querybuf;
vdev->vidioc_qbuf = soc_camera_qbuf;
vdev->vidioc_dqbuf = soc_camera_dqbuf;
@@ -985,7 +983,7 @@ void soc_camera_video_stop(struct soc_camera_device *icd)
{
struct video_device *vdev = icd->vdev;
- dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&icd->dev, "%s\n", __func__);
if (!icd->dev.parent || !vdev)
return;
diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c
index 015f6a53f..28abeec05 100644
--- a/linux/drivers/media/video/stk-webcam.c
+++ b/linux/drivers/media/video/stk-webcam.c
@@ -30,6 +30,7 @@
#include <linux/kref.h>
#include <linux/usb.h>
+#include <linux/mm.h>
#include <linux/vmalloc.h>
#include "compat.h"
#include <linux/videodev2.h>
@@ -246,6 +247,8 @@ static int stk_initialise(struct stk_camera *dev)
return -1;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+
/* sysfs functions */
/*FIXME cleanup this */
@@ -351,6 +354,10 @@ static void stk_remove_sysfs_files(struct video_device *vdev)
video_device_remove_file(vdev, &dev_attr_vflip);
}
+#else
+#define stk_create_sysfs_files(a)
+#define stk_remove_sysfs_files(a)
+#endif
/* *********************************************** */
/*
@@ -975,7 +982,7 @@ static int stk_vidioc_s_ctrl(struct file *filp,
}
-static int stk_vidioc_enum_fmt_cap(struct file *filp,
+static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_fmtdesc *fmtd)
{
fmtd->flags = 0;
@@ -1019,7 +1026,7 @@ static struct stk_size {
{ .w = 176, .h = 144, .m = MODE_QCIF, },
};
-static int stk_vidioc_g_fmt_cap(struct file *filp,
+static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_format *f)
{
struct v4l2_pix_format *pix_format = &f->fmt.pix;
@@ -1048,7 +1055,7 @@ static int stk_vidioc_g_fmt_cap(struct file *filp,
return 0;
}
-static int stk_vidioc_try_fmt_cap(struct file *filp,
+static int stk_vidioc_try_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_format *fmtd)
{
int i;
@@ -1101,7 +1108,7 @@ static int stk_setup_format(struct stk_camera *dev)
&& i < ARRAY_SIZE(stk_sizes))
i++;
if (i == ARRAY_SIZE(stk_sizes)) {
- STK_ERROR("Something is broken in %s\n", __FUNCTION__);
+ STK_ERROR("Something is broken in %s\n", __func__);
return -EFAULT;
}
/* This registers controls some timings, not sure of what. */
@@ -1125,7 +1132,7 @@ static int stk_setup_format(struct stk_camera *dev)
return stk_sensor_configure(dev);
}
-static int stk_vidioc_s_fmt_cap(struct file *filp,
+static int stk_vidioc_s_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_format *fmtd)
{
int ret;
@@ -1139,7 +1146,7 @@ static int stk_vidioc_s_fmt_cap(struct file *filp,
return -EBUSY;
if (dev->owner && dev->owner != filp)
return -EBUSY;
- ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd);
+ ret = stk_vidioc_try_fmt_vid_cap(filp, priv, fmtd);
if (ret)
return ret;
dev->owner = filp;
@@ -1336,10 +1343,10 @@ static struct video_device stk_v4l_data = {
.release = stk_v4l_dev_release,
.vidioc_querycap = stk_vidioc_querycap,
- .vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap,
- .vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap,
- .vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap,
+ .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = stk_vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = stk_vidioc_g_fmt_vid_cap,
.vidioc_enum_input = stk_vidioc_enum_input,
.vidioc_s_input = stk_vidioc_s_input,
.vidioc_g_input = stk_vidioc_g_input,
diff --git a/linux/drivers/media/video/stv680.c b/linux/drivers/media/video/stv680.c
index dfbb63b93..8bc396533 100644
--- a/linux/drivers/media/video/stv680.c
+++ b/linux/drivers/media/video/stv680.c
@@ -86,7 +86,7 @@ static unsigned int debug;
#define PDEBUG(level, fmt, args...) \
do { \
if (debug >= level) \
- info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \
+ info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
} while (0)
diff --git a/linux/drivers/media/video/tcm825x.c b/linux/drivers/media/video/tcm825x.c
index fb895f668..08c7888e5 100644
--- a/linux/drivers/media/video/tcm825x.c
+++ b/linux/drivers/media/video/tcm825x.c
@@ -523,6 +523,9 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s,
if (val < 0)
return val;
+ if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
+ val ^= sensor->platform_data->is_upside_down();
+
vc->value = val;
return 0;
}
@@ -556,6 +559,9 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s,
if (lvc == NULL)
return -EINVAL;
+ if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
+ val ^= sensor->platform_data->is_upside_down();
+
val = val << lvc->start_bit;
if (tcm825x_write_reg_mask(client, lvc->reg, val))
return -EIO;
@@ -840,7 +846,8 @@ static struct v4l2_int_device tcm825x_int_device = {
},
};
-static int tcm825x_probe(struct i2c_client *client)
+static int tcm825x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct tcm825x_sensor *sensor = &tcm825x;
int rval;
@@ -884,12 +891,23 @@ static int __exit tcm825x_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tcm825x_id[] = {
+ { "tcm825x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tcm825x_id);
+#endif
+
static struct i2c_driver tcm825x_i2c_driver = {
.driver = {
.name = TCM825X_NAME,
},
.probe = tcm825x_probe,
.remove = __exit_p(tcm825x_remove),
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tcm825x_id,
+#endif
};
static struct tcm825x_sensor tcm825x = {
@@ -906,7 +924,7 @@ static int __init tcm825x_init(void)
rval = i2c_add_driver(&tcm825x_i2c_driver);
if (rval)
printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
- __FUNCTION__);
+ __func__);
return rval;
}
diff --git a/linux/drivers/media/video/tcm825x.h b/linux/drivers/media/video/tcm825x.h
index 966765b66..770ebacfa 100644
--- a/linux/drivers/media/video/tcm825x.h
+++ b/linux/drivers/media/video/tcm825x.h
@@ -182,6 +182,7 @@ struct tcm825x_platform_data {
int (*needs_reset)(struct v4l2_int_device *s, void *buf,
struct v4l2_pix_format *fmt);
int (*ifparm)(struct v4l2_ifparm *p);
+ int (*is_upside_down)(void);
};
/* Array of image sizes supported by TCM825X. These must be ordered from
diff --git a/linux/drivers/media/video/tda8290.c b/linux/drivers/media/video/tda8290.c
deleted file mode 100644
index 789548828..000000000
--- a/linux/drivers/media/video/tda8290.c
+++ /dev/null
@@ -1,833 +0,0 @@
-/*
-
- i2c tv tuner chip device driver
- controls the philips tda8290+75 tuner chip combo.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- This "tda8290" module was split apart from the original "tuner" module.
-*/
-
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include "compat.h"
-#include <linux/videodev.h>
-#include "tuner-i2c.h"
-#include "tda8290.h"
-#include "tda827x.h"
-#include "tda18271.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-/* ---------------------------------------------------------------------- */
-
-struct tda8290_priv {
- struct tuner_i2c_props i2c_props;
-
- unsigned char tda8290_easy_mode;
-
- unsigned char tda827x_addr;
-
- unsigned char ver;
-#define TDA8290 1
-#define TDA8295 2
-#define TDA8275 4
-#define TDA8275A 8
-#define TDA18271 16
-
- struct tda827x_config cfg;
-};
-
-/*---------------------------------------------------------------------*/
-
-static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char enable[2] = { 0x21, 0xC0 };
- unsigned char disable[2] = { 0x21, 0x00 };
- unsigned char *msg;
-
- if (close) {
- msg = enable;
- tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
- /* let the bridge stabilize */
- msleep(20);
- } else {
- msg = disable;
- tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
- }
-
- return 0;
-}
-
-#if 1
-static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char enable[2] = { 0x45, 0xc1 };
- unsigned char disable[2] = { 0x46, 0x00 };
- unsigned char buf[3] = { 0x45, 0x01, 0x00 };
- unsigned char *msg;
-
- if (close) {
- msg = enable;
- tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
- /* let the bridge stabilize */
- msleep(20);
- } else {
- msg = disable;
- tuner_i2c_xfer_send(&priv->i2c_props, msg, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1);
-
- buf[2] = msg[1];
- buf[2] &= ~0x04;
- tuner_i2c_xfer_send(&priv->i2c_props, buf, 3);
- msleep(5);
-
- msg[1] |= 0x04;
- tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
- }
-
- return 0;
-}
-#else
-static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char buf[] = { 0x45, 0x00 };
-
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
-
- buf[1] &= 0x3f;
- if (close)
- buf[1] |= 0xc0;
- else
- buf[1] |= 0x80;
-
- tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-
- return 0;
-}
-#endif
-
-/*---------------------------------------------------------------------*/
-
-static void set_audio(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
- char* mode;
-
- if (params->std & V4L2_STD_MN) {
- priv->tda8290_easy_mode = 0x01;
- mode = "MN";
- } else if (params->std & V4L2_STD_B) {
- priv->tda8290_easy_mode = 0x02;
- mode = "B";
- } else if (params->std & V4L2_STD_GH) {
- priv->tda8290_easy_mode = 0x04;
- mode = "GH";
- } else if (params->std & V4L2_STD_PAL_I) {
- priv->tda8290_easy_mode = 0x08;
- mode = "I";
- } else if (params->std & V4L2_STD_DK) {
- priv->tda8290_easy_mode = 0x10;
- mode = "DK";
- } else if (params->std & V4L2_STD_SECAM_L) {
- priv->tda8290_easy_mode = 0x20;
- mode = "L";
- } else if (params->std & V4L2_STD_SECAM_LC) {
- priv->tda8290_easy_mode = 0x40;
- mode = "LC";
- } else {
- priv->tda8290_easy_mode = 0x10;
- mode = "xx";
- }
-
- tuner_dbg("setting tda829x to system %s\n", mode);
-}
-
-static void tda8290_set_params(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char soft_reset[] = { 0x00, 0x00 };
- unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode };
- unsigned char expert_mode[] = { 0x01, 0x80 };
- unsigned char agc_out_on[] = { 0x02, 0x00 };
- unsigned char gainset_off[] = { 0x28, 0x14 };
- unsigned char if_agc_spd[] = { 0x0f, 0x88 };
- unsigned char adc_head_6[] = { 0x05, 0x04 };
- unsigned char adc_head_9[] = { 0x05, 0x02 };
- unsigned char adc_head_12[] = { 0x05, 0x01 };
- unsigned char pll_bw_nom[] = { 0x0d, 0x47 };
- unsigned char pll_bw_low[] = { 0x0d, 0x27 };
- unsigned char gainset_2[] = { 0x28, 0x64 };
- unsigned char agc_rst_on[] = { 0x0e, 0x0b };
- unsigned char agc_rst_off[] = { 0x0e, 0x09 };
- unsigned char if_agc_set[] = { 0x0f, 0x81 };
- unsigned char addr_adc_sat = 0x1a;
- unsigned char addr_agc_stat = 0x1d;
- unsigned char addr_pll_stat = 0x1b;
- unsigned char adc_sat, agc_stat,
- pll_stat;
- int i;
-
- set_audio(fe, params);
-
- if (priv->cfg.config)
- tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config);
- tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
- msleep(1);
-
- expert_mode[1] = priv->tda8290_easy_mode + 0x80;
- tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
- if (priv->tda8290_easy_mode & 0x60)
- tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
- else
- tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
-
- tda8290_i2c_bridge(fe, 1);
-
- if (fe->ops.tuner_ops.set_analog_params)
- fe->ops.tuner_ops.set_analog_params(fe, params);
-
- for (i = 0; i < 3; i++) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
- if (pll_stat & 0x80) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
- tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
- break;
- } else {
- tuner_dbg("tda8290 not locked, no signal?\n");
- msleep(100);
- }
- }
- /* adjust headroom resp. gain */
- if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
- tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
- agc_stat, adc_sat, pll_stat & 0x80);
- tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
- msleep(100);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
- if ((agc_stat > 115) || !(pll_stat & 0x80)) {
- tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
- agc_stat, pll_stat & 0x80);
- if (priv->cfg.agcf)
- priv->cfg.agcf(fe);
- msleep(100);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
- if((agc_stat > 115) || !(pll_stat & 0x80)) {
- tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
- tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2);
- msleep(100);
- }
- }
- }
-
- /* l/ l' deadlock? */
- if(priv->tda8290_easy_mode & 0x60) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
- if ((adc_sat > 20) || !(pll_stat & 0x80)) {
- tuner_dbg("trying to resolve SECAM L deadlock\n");
- tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
- msleep(40);
- tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2);
- }
- }
-
- tda8290_i2c_bridge(fe, 0);
- tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda8295_power(struct dvb_frontend *fe, int enable)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
- unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
-
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
-
- if (enable)
- buf[1] = 0x01;
- else
- buf[1] = 0x03;
-
- tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-}
-
-static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
- unsigned char buf[] = { 0x01, 0x00 };
-
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
-
- if (enable)
- buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
- else
- buf[1] = 0x00; /* reset active bit */
-
- tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-}
-
-static void tda8295_set_video_std(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
- unsigned char buf[] = { 0x00, priv->tda8290_easy_mode };
-
- tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-
- tda8295_set_easy_mode(fe, 1);
- msleep(20);
- tda8295_set_easy_mode(fe, 0);
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
- unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
-
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
-
- if (enable)
- buf[1] &= ~0x40;
- else
- buf[1] |= 0x40;
-
- tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
-}
-
-static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
- unsigned char set_gpio_cf[] = { 0x44, 0x00 };
- unsigned char set_gpio_val[] = { 0x46, 0x00 };
-
- tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1);
-
- set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
-
- if (enable) {
- set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */
- set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */
- }
- tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2);
-}
-
-static int tda8295_has_signal(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char hvpll_stat = 0x26;
- unsigned char ret;
-
- tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1);
- return (ret & 0x01) ? 65535 : 0;
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda8295_set_params(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char blanking_mode[] = { 0x1d, 0x00 };
-
- set_audio(fe, params);
-
- tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency);
-
- tda8295_power(fe, 1);
- tda8295_agc1_out(fe, 1);
-
- tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1);
-
- tda8295_set_video_std(fe);
-
- blanking_mode[1] = 0x03;
- tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2);
- msleep(20);
-
- tda8295_i2c_bridge(fe, 1);
-
- if (fe->ops.tuner_ops.set_analog_params)
- fe->ops.tuner_ops.set_analog_params(fe, params);
-
- if (priv->cfg.agcf)
- priv->cfg.agcf(fe);
-
- if (tda8295_has_signal(fe))
- tuner_dbg("tda8295 is locked\n");
- else
- tuner_dbg("tda8295 not locked, no signal?\n");
-
- tda8295_i2c_bridge(fe, 0);
-}
-
-/*---------------------------------------------------------------------*/
-
-static int tda8290_has_signal(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char i2c_get_afc[1] = { 0x1B };
- unsigned char afc = 0;
-
- tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
- tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
- return (afc & 0x80)? 65535:0;
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda8290_standby(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char cb1[] = { 0x30, 0xD0 };
- unsigned char tda8290_standby[] = { 0x00, 0x02 };
- unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
- struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
-
- tda8290_i2c_bridge(fe, 1);
- if (priv->ver & TDA8275A)
- cb1[1] = 0x90;
- i2c_transfer(priv->i2c_props.adap, &msg, 1);
- tda8290_i2c_bridge(fe, 0);
- tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
-}
-
-static void tda8295_standby(struct dvb_frontend *fe)
-{
- tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */
-
- tda8295_power(fe, 0);
-}
-
-static void tda8290_init_if(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- unsigned char set_VS[] = { 0x30, 0x6F };
- unsigned char set_GP00_CF[] = { 0x20, 0x01 };
- unsigned char set_GP01_CF[] = { 0x20, 0x0B };
-
- if ((priv->cfg.config == 1) || (priv->cfg.config == 2))
- tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
- else
- tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
-}
-
-static void tda8295_init_if(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- static unsigned char set_adc_ctl[] = { 0x33, 0x14 };
- static unsigned char set_adc_ctl2[] = { 0x34, 0x00 };
- static unsigned char set_pll_reg6[] = { 0x3e, 0x63 };
- static unsigned char set_pll_reg0[] = { 0x38, 0x23 };
- static unsigned char set_pll_reg7[] = { 0x3f, 0x01 };
- static unsigned char set_pll_reg10[] = { 0x42, 0x61 };
- static unsigned char set_gpio_reg0[] = { 0x44, 0x0b };
-
- tda8295_power(fe, 1);
-
- tda8295_set_easy_mode(fe, 0);
- tda8295_set_video_std(fe);
-
- tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2);
- tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2);
-
- tda8295_agc1_out(fe, 0);
- tda8295_agc2_out(fe, 0);
-}
-
-static void tda8290_init_tuner(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
- unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
- 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
- unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
- 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
- struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
- .buf=tda8275_init, .len = 14};
- if (priv->ver & TDA8275A)
- msg.buf = tda8275a_init;
-
- tda8290_i2c_bridge(fe, 1);
- i2c_transfer(priv->i2c_props.adap, &msg, 1);
- tda8290_i2c_bridge(fe, 0);
-}
-
-/*---------------------------------------------------------------------*/
-
-static void tda829x_release(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
-
- /* only try to release the tuner if we've
- * attached it from within this module */
- if (priv->ver & (TDA18271 | TDA8275 | TDA8275A))
- if (fe->ops.tuner_ops.release)
- fe->ops.tuner_ops.release(fe);
-
- kfree(fe->analog_demod_priv);
- fe->analog_demod_priv = NULL;
-}
-
-static struct tda18271_config tda829x_tda18271_config = {
- .gate = TDA18271_GATE_ANALOG,
-};
-
-static int tda829x_find_tuner(struct dvb_frontend *fe)
-{
- struct tda8290_priv *priv = fe->analog_demod_priv;
- struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
- int i, ret, tuners_found;
- u32 tuner_addrs;
- u8 data;
- struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
-
- if (NULL == analog_ops->i2c_gate_ctrl)
- return -EINVAL;
-
- analog_ops->i2c_gate_ctrl(fe, 1);
-
- /* probe for tuner chip */
- tuners_found = 0;
- tuner_addrs = 0;
- for (i = 0x60; i <= 0x63; i++) {
- msg.addr = i;
- ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
- if (ret == 1) {
- tuners_found++;
- tuner_addrs = (tuner_addrs << 8) + i;
- }
- }
- /* if there is more than one tuner, we expect the right one is
- behind the bridge and we choose the highest address that doesn't
- give a response now
- */
-
- analog_ops->i2c_gate_ctrl(fe, 0);
-
- if (tuners_found > 1)
- for (i = 0; i < tuners_found; i++) {
- msg.addr = tuner_addrs & 0xff;
- ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
- if (ret == 1)
- tuner_addrs = tuner_addrs >> 8;
- else
- break;
- }
-
- if (tuner_addrs == 0) {
- tuner_addrs = 0x60;
- tuner_info("could not clearly identify tuner address, "
- "defaulting to %x\n", tuner_addrs);
- } else {
- tuner_addrs = tuner_addrs & 0xff;
- tuner_info("setting tuner address to %x\n", tuner_addrs);
- }
- priv->tda827x_addr = tuner_addrs;
- msg.addr = tuner_addrs;
-
- analog_ops->i2c_gate_ctrl(fe, 1);
- ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
- if (ret != 1) {
- tuner_warn("tuner access failed!\n");
- return -EREMOTEIO;
- }
-
- if ((data == 0x83) || (data == 0x84)) {
- priv->ver |= TDA18271;
- tda18271_attach(fe, priv->tda827x_addr,
- priv->i2c_props.adap,
- &tda829x_tda18271_config);
- } else {
- if ((data & 0x3c) == 0)
- priv->ver |= TDA8275;
- else
- priv->ver |= TDA8275A;
-
- tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg);
- priv->cfg.switch_addr = priv->i2c_props.addr;
- }
- if (fe->ops.tuner_ops.init)
- fe->ops.tuner_ops.init(fe);
-
- if (fe->ops.tuner_ops.sleep)
- fe->ops.tuner_ops.sleep(fe);
-
- analog_ops->i2c_gate_ctrl(fe, 0);
-
- return 0;
-}
-
-static int tda8290_probe(struct tuner_i2c_props *i2c_props)
-{
-#define TDA8290_ID 0x89
- unsigned char tda8290_id[] = { 0x1f, 0x00 };
-
- /* detect tda8290 */
- tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1);
- tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1);
-
- if (tda8290_id[1] == TDA8290_ID) {
- if (debug)
- printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
- __FUNCTION__, i2c_adapter_id(i2c_props->adap),
- i2c_props->addr);
- return 0;
- }
-
- return -ENODEV;
-}
-
-static int tda8295_probe(struct tuner_i2c_props *i2c_props)
-{
-#define TDA8295_ID 0x8a
- unsigned char tda8295_id[] = { 0x2f, 0x00 };
-
- /* detect tda8295 */
- tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
- tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
-
- if (tda8295_id[1] == TDA8295_ID) {
- if (debug)
- printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
- __FUNCTION__, i2c_adapter_id(i2c_props->adap),
- i2c_props->addr);
- return 0;
- }
-
- return -ENODEV;
-}
-
-static struct analog_demod_ops tda8290_ops = {
- .set_params = tda8290_set_params,
- .has_signal = tda8290_has_signal,
- .standby = tda8290_standby,
- .release = tda829x_release,
- .i2c_gate_ctrl = tda8290_i2c_bridge,
-};
-
-static struct analog_demod_ops tda8295_ops = {
- .set_params = tda8295_set_params,
- .has_signal = tda8295_has_signal,
- .standby = tda8295_standby,
- .release = tda829x_release,
- .i2c_gate_ctrl = tda8295_i2c_bridge,
-};
-
-struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap, u8 i2c_addr,
- struct tda829x_config *cfg)
-{
- struct tda8290_priv *priv = NULL;
- char *name;
-
- priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
- fe->analog_demod_priv = priv;
-
- priv->i2c_props.addr = i2c_addr;
- priv->i2c_props.adap = i2c_adap;
- priv->i2c_props.name = "tda829x";
- if (cfg) {
- priv->cfg.config = cfg->lna_cfg;
- priv->cfg.tuner_callback = cfg->tuner_callback;
- }
-
- if (tda8290_probe(&priv->i2c_props) == 0) {
- priv->ver = TDA8290;
- memcpy(&fe->ops.analog_ops, &tda8290_ops,
- sizeof(struct analog_demod_ops));
- }
-
- if (tda8295_probe(&priv->i2c_props) == 0) {
- priv->ver = TDA8295;
- memcpy(&fe->ops.analog_ops, &tda8295_ops,
- sizeof(struct analog_demod_ops));
- }
-
- if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) &&
- (tda829x_find_tuner(fe) < 0))
- goto fail;
-
- switch (priv->ver) {
- case TDA8290:
- name = "tda8290";
- break;
- case TDA8295:
- name = "tda8295";
- break;
- case TDA8290 | TDA8275:
- name = "tda8290+75";
- break;
- case TDA8295 | TDA8275:
- name = "tda8295+75";
- break;
- case TDA8290 | TDA8275A:
- name = "tda8290+75a";
- break;
- case TDA8295 | TDA8275A:
- name = "tda8295+75a";
- break;
- case TDA8290 | TDA18271:
- name = "tda8290+18271";
- break;
- case TDA8295 | TDA18271:
- name = "tda8295+18271";
- break;
- default:
- goto fail;
- }
- tuner_info("type set to %s\n", name);
-
- fe->ops.analog_ops.info.name = name;
-
- if (priv->ver & TDA8290) {
- tda8290_init_tuner(fe);
- tda8290_init_if(fe);
- } else if (priv->ver & TDA8295)
- tda8295_init_if(fe);
-
-#if 0
- t->mode = V4L2_TUNER_ANALOG_TV;
-#endif
- return fe;
-
-fail:
- tda829x_release(fe);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(tda829x_attach);
-
-int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
-{
- struct tuner_i2c_props i2c_props = {
- .adap = i2c_adap,
- .addr = i2c_addr,
- };
-
- unsigned char soft_reset[] = { 0x00, 0x00 };
- unsigned char easy_mode_b[] = { 0x01, 0x02 };
- unsigned char easy_mode_g[] = { 0x01, 0x04 };
- unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 };
- unsigned char addr_dto_lsb = 0x07;
- unsigned char data;
-#define PROBE_BUFFER_SIZE 8
- unsigned char buf[PROBE_BUFFER_SIZE];
- int i;
-
- /* rule out tda9887, which would return the same byte repeatedly */
- tuner_i2c_xfer_send(&i2c_props, soft_reset, 1);
- tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE);
- for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
- if (buf[i] != buf[0])
- break;
- }
-
- /* all bytes are equal, not a tda829x - probably a tda9887 */
- if (i == PROBE_BUFFER_SIZE)
- return -ENODEV;
-
- if ((tda8290_probe(&i2c_props) == 0) ||
- (tda8295_probe(&i2c_props) == 0))
- return 0;
-
- /* fall back to old probing method */
- tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
- tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
- tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
- tuner_i2c_xfer_recv(&i2c_props, &data, 1);
- if (data == 0) {
- tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
- tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
- tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
- tuner_i2c_xfer_recv(&i2c_props, &data, 1);
- if (data == 0x7b) {
- return 0;
- }
- }
- tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
- return -ENODEV;
-}
-EXPORT_SYMBOL_GPL(tda829x_probe);
-
-MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
-MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/linux/drivers/media/video/tda8290.h b/linux/drivers/media/video/tda8290.h
deleted file mode 100644
index 9dd8b73eb..000000000
--- a/linux/drivers/media/video/tda8290.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TDA8290_H__
-#define __TDA8290_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-struct tda829x_config {
- unsigned int lna_cfg;
- int (*tuner_callback) (void *dev, int command, int arg);
-
- unsigned int probe_tuner:1;
-#define TDA829X_PROBE_TUNER 0
-#define TDA829X_DONT_PROBE 1
-};
-
-#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
-extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
-
-extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr,
- struct tda829x_config *cfg);
-#else
-static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- return -EINVAL;
-}
-
-static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr,
- struct tda829x_config *cfg)
-{
- printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
- __FUNCTION__);
- return NULL;
-}
-#endif
-
-#endif /* __TDA8290_H__ */
diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c
index 8218f466d..c41e50ba6 100644
--- a/linux/drivers/media/video/tda9840.c
+++ b/linux/drivers/media/video/tda9840.c
@@ -37,10 +37,10 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __func__, __LINE__); printk(args); } } while (0)
#else
#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
#endif
#define SWITCH 0x00
@@ -181,7 +181,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind)
/* allocate memory for client structure */
client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (0 == client) {
+ if (!client) {
printk("not enough kernel memory\n");
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/tda9887.c b/linux/drivers/media/video/tda9887.c
deleted file mode 100644
index e98de7d40..000000000
--- a/linux/drivers/media/video/tda9887.c
+++ /dev/null
@@ -1,728 +0,0 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "compat.h"
-#include <linux/videodev.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-#include <media/v4l2-common.h>
-#include <media/tuner.h>
-#include "tuner-i2c.h"
-#include "tda9887.h"
-
-
-/* Chips:
- TDA9885 (PAL, NTSC)
- TDA9886 (PAL, SECAM, NTSC)
- TDA9887 (PAL, SECAM, NTSC, FM Radio)
-
- Used as part of several tuners
-*/
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static DEFINE_MUTEX(tda9887_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-struct tda9887_priv {
- struct tuner_i2c_props i2c_props;
- struct list_head hybrid_tuner_instance_list;
-
- unsigned char data[4];
- unsigned int config;
- unsigned int mode;
- unsigned int audmode;
- v4l2_std_id std;
-};
-
-/* ---------------------------------------------------------------------- */
-
-#define UNSET (-1U)
-
-struct tvnorm {
- v4l2_std_id std;
- char *name;
- unsigned char b;
- unsigned char c;
- unsigned char e;
-};
-
-/* ---------------------------------------------------------------------- */
-
-//
-// TDA defines
-//
-
-//// first reg (b)
-#define cVideoTrapBypassOFF 0x00 // bit b0
-#define cVideoTrapBypassON 0x01 // bit b0
-
-#define cAutoMuteFmInactive 0x00 // bit b1
-#define cAutoMuteFmActive 0x02 // bit b1
-
-#define cIntercarrier 0x00 // bit b2
-#define cQSS 0x04 // bit b2
-
-#define cPositiveAmTV 0x00 // bit b3:4
-#define cFmRadio 0x08 // bit b3:4
-#define cNegativeFmTV 0x10 // bit b3:4
-
-
-#define cForcedMuteAudioON 0x20 // bit b5
-#define cForcedMuteAudioOFF 0x00 // bit b5
-
-#define cOutputPort1Active 0x00 // bit b6
-#define cOutputPort1Inactive 0x40 // bit b6
-
-#define cOutputPort2Active 0x00 // bit b7
-#define cOutputPort2Inactive 0x80 // bit b7
-
-
-//// second reg (c)
-#define cDeemphasisOFF 0x00 // bit c5
-#define cDeemphasisON 0x20 // bit c5
-
-#define cDeemphasis75 0x00 // bit c6
-#define cDeemphasis50 0x40 // bit c6
-
-#define cAudioGain0 0x00 // bit c7
-#define cAudioGain6 0x80 // bit c7
-
-#define cTopMask 0x1f // bit c0:4
-#define cTopDefault 0x10 // bit c0:4
-
-//// third reg (e)
-#define cAudioIF_4_5 0x00 // bit e0:1
-#define cAudioIF_5_5 0x01 // bit e0:1
-#define cAudioIF_6_0 0x02 // bit e0:1
-#define cAudioIF_6_5 0x03 // bit e0:1
-
-
-#define cVideoIFMask 0x1c // bit e2:4
-/* Video IF selection in TV Mode (bit B3=0) */
-#define cVideoIF_58_75 0x00 // bit e2:4
-#define cVideoIF_45_75 0x04 // bit e2:4
-#define cVideoIF_38_90 0x08 // bit e2:4
-#define cVideoIF_38_00 0x0C // bit e2:4
-#define cVideoIF_33_90 0x10 // bit e2:4
-#define cVideoIF_33_40 0x14 // bit e2:4
-#define cRadioIF_45_75 0x18 // bit e2:4
-#define cRadioIF_38_90 0x1C // bit e2:4
-
-/* IF1 selection in Radio Mode (bit B3=1) */
-#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
-#define cRadioIF_41_30 0x04 // bit e2,4
-
-/* Output of AFC pin in radio mode when bit E7=1 */
-#define cRadioAGC_SIF 0x00 // bit e3
-#define cRadioAGC_FM 0x08 // bit e3
-
-#define cTunerGainNormal 0x00 // bit e5
-#define cTunerGainLow 0x20 // bit e5
-
-#define cGating_18 0x00 // bit e6
-#define cGating_36 0x40 // bit e6
-
-#define cAgcOutON 0x80 // bit e7
-#define cAgcOutOFF 0x00 // bit e7
-
-/* ---------------------------------------------------------------------- */
-
-static struct tvnorm tvnorms[] = {
- {
- .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N,
- .name = "PAL-BGHN",
- .b = ( cNegativeFmTV |
- cQSS ),
- .c = ( cDeemphasisON |
- cDeemphasis50 |
- cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_5_5 |
- cVideoIF_38_90 ),
- },{
- .std = V4L2_STD_PAL_I,
- .name = "PAL-I",
- .b = ( cNegativeFmTV |
- cQSS ),
- .c = ( cDeemphasisON |
- cDeemphasis50 |
- cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_6_0 |
- cVideoIF_38_90 ),
- },{
- .std = V4L2_STD_PAL_DK,
- .name = "PAL-DK",
- .b = ( cNegativeFmTV |
- cQSS ),
- .c = ( cDeemphasisON |
- cDeemphasis50 |
- cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_6_5 |
- cVideoIF_38_90 ),
- },{
- .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc,
- .name = "PAL-M/Nc",
- .b = ( cNegativeFmTV |
- cQSS ),
- .c = ( cDeemphasisON |
- cDeemphasis75 |
- cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_4_5 |
- cVideoIF_45_75 ),
- },{
- .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
- .name = "SECAM-BGH",
- .b = ( cPositiveAmTV |
- cQSS ),
- .c = ( cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_5_5 |
- cVideoIF_38_90 ),
- },{
- .std = V4L2_STD_SECAM_L,
- .name = "SECAM-L",
- .b = ( cPositiveAmTV |
- cQSS ),
- .c = ( cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_6_5 |
- cVideoIF_38_90 ),
- },{
- .std = V4L2_STD_SECAM_LC,
- .name = "SECAM-L'",
- .b = ( cOutputPort2Inactive |
- cPositiveAmTV |
- cQSS ),
- .c = ( cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_6_5 |
- cVideoIF_33_90 ),
- },{
- .std = V4L2_STD_SECAM_DK,
- .name = "SECAM-DK",
- .b = ( cNegativeFmTV |
- cQSS ),
- .c = ( cDeemphasisON |
- cDeemphasis50 |
- cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_6_5 |
- cVideoIF_38_90 ),
- },{
- .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
- .name = "NTSC-M",
- .b = ( cNegativeFmTV |
- cQSS ),
- .c = ( cDeemphasisON |
- cDeemphasis75 |
- cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_4_5 |
- cVideoIF_45_75 ),
- },{
- .std = V4L2_STD_NTSC_M_JP,
- .name = "NTSC-M-JP",
- .b = ( cNegativeFmTV |
- cQSS ),
- .c = ( cDeemphasisON |
- cDeemphasis50 |
- cTopDefault),
- .e = ( cGating_36 |
- cAudioIF_4_5 |
- cVideoIF_58_75 ),
- }
-};
-
-static struct tvnorm radio_stereo = {
- .name = "Radio Stereo",
- .b = ( cFmRadio |
- cQSS ),
- .c = ( cDeemphasisOFF |
- cAudioGain6 |
- cTopDefault),
- .e = ( cTunerGainLow |
- cAudioIF_5_5 |
- cRadioIF_38_90 ),
-};
-
-static struct tvnorm radio_mono = {
- .name = "Radio Mono",
- .b = ( cFmRadio |
- cQSS ),
- .c = ( cDeemphasisON |
- cDeemphasis75 |
- cTopDefault),
- .e = ( cTunerGainLow |
- cAudioIF_5_5 |
- cRadioIF_38_90 ),
-};
-
-/* ---------------------------------------------------------------------- */
-
-static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
-
- static char *afc[16] = {
- "- 12.5 kHz",
- "- 37.5 kHz",
- "- 62.5 kHz",
- "- 87.5 kHz",
- "-112.5 kHz",
- "-137.5 kHz",
- "-162.5 kHz",
- "-187.5 kHz [min]",
- "+187.5 kHz [max]",
- "+162.5 kHz",
- "+137.5 kHz",
- "+112.5 kHz",
- "+ 87.5 kHz",
- "+ 62.5 kHz",
- "+ 37.5 kHz",
- "+ 12.5 kHz",
- };
- tuner_info("read: 0x%2x\n", buf[0]);
- tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
- tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
- tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
- tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
- tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
-}
-
-static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
-
- static char *sound[4] = {
- "AM/TV",
- "FM/radio",
- "FM/TV",
- "FM/radio"
- };
- static char *adjust[32] = {
- "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9",
- "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1",
- "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7",
- "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15"
- };
- static char *deemph[4] = {
- "no", "no", "75", "50"
- };
- static char *carrier[4] = {
- "4.5 MHz",
- "5.5 MHz",
- "6.0 MHz",
- "6.5 MHz / AM"
- };
- static char *vif[8] = {
- "58.75 MHz",
- "45.75 MHz",
- "38.9 MHz",
- "38.0 MHz",
- "33.9 MHz",
- "33.4 MHz",
- "45.75 MHz + pin13",
- "38.9 MHz + pin13",
- };
- static char *rif[4] = {
- "44 MHz",
- "52 MHz",
- "52 MHz",
- "44 MHz",
- };
-
- tuner_info("write: byte B 0x%02x\n", buf[1]);
- tuner_info(" B0 video mode : %s\n",
- (buf[1] & 0x01) ? "video trap" : "sound trap");
- tuner_info(" B1 auto mute fm : %s\n",
- (buf[1] & 0x02) ? "yes" : "no");
- tuner_info(" B2 carrier mode : %s\n",
- (buf[1] & 0x04) ? "QSS" : "Intercarrier");
- tuner_info(" B3-4 tv sound/radio : %s\n",
- sound[(buf[1] & 0x18) >> 3]);
- tuner_info(" B5 force mute audio: %s\n",
- (buf[1] & 0x20) ? "yes" : "no");
- tuner_info(" B6 output port 1 : %s\n",
- (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
- tuner_info(" B7 output port 2 : %s\n",
- (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
-
- tuner_info("write: byte C 0x%02x\n", buf[2]);
- tuner_info(" C0-4 top adjustment : %s dB\n",
- adjust[buf[2] & 0x1f]);
- tuner_info(" C5-6 de-emphasis : %s\n",
- deemph[(buf[2] & 0x60) >> 5]);
- tuner_info(" C7 audio gain : %s\n",
- (buf[2] & 0x80) ? "-6" : "0");
-
- tuner_info("write: byte E 0x%02x\n", buf[3]);
- tuner_info(" E0-1 sound carrier : %s\n",
- carrier[(buf[3] & 0x03)]);
- tuner_info(" E6 l pll gating : %s\n",
- (buf[3] & 0x40) ? "36" : "13");
-
- if (buf[1] & 0x08) {
- /* radio */
- tuner_info(" E2-4 video if : %s\n",
- rif[(buf[3] & 0x0c) >> 2]);
- tuner_info(" E7 vif agc output : %s\n",
- (buf[3] & 0x80)
- ? ((buf[3] & 0x10) ? "fm-agc radio" :
- "sif-agc radio")
- : "fm radio carrier afc");
- } else {
- /* video */
- tuner_info(" E2-4 video if : %s\n",
- vif[(buf[3] & 0x1c) >> 2]);
- tuner_info(" E5 tuner gain : %s\n",
- (buf[3] & 0x80)
- ? ((buf[3] & 0x20) ? "external" : "normal")
- : ((buf[3] & 0x20) ? "minimum" : "normal"));
- tuner_info(" E7 vif agc output : %s\n",
- (buf[3] & 0x80) ? ((buf[3] & 0x20)
- ? "pin3 port, pin22 vif agc out"
- : "pin22 port, pin3 vif acg ext in")
- : "pin3+pin22 port");
- }
- tuner_info("--\n");
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tda9887_set_tvnorm(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
- struct tvnorm *norm = NULL;
- char *buf = priv->data;
- int i;
-
- if (priv->mode == V4L2_TUNER_RADIO) {
- if (priv->audmode == V4L2_TUNER_MODE_MONO)
- norm = &radio_mono;
- else
- norm = &radio_stereo;
- } else {
- for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
- if (tvnorms[i].std & priv->std) {
- norm = tvnorms+i;
- break;
- }
- }
- }
- if (NULL == norm) {
- tuner_dbg("Unsupported tvnorm entry - audio muted\n");
- return -1;
- }
-
- tuner_dbg("configure for: %s\n", norm->name);
- buf[1] = norm->b;
- buf[2] = norm->c;
- buf[3] = norm->e;
- return 0;
-}
-
-static unsigned int port1 = UNSET;
-static unsigned int port2 = UNSET;
-static unsigned int qss = UNSET;
-static unsigned int adjust = UNSET;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(port1, "i");
-MODULE_PARM(port2, "i");
-MODULE_PARM(qss, "i");
-MODULE_PARM(adjust, "i");
-#else
-module_param(port1, int, 0644);
-module_param(port2, int, 0644);
-module_param(qss, int, 0644);
-module_param(adjust, int, 0644);
-#endif
-
-static int tda9887_set_insmod(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
- char *buf = priv->data;
-
- if (UNSET != port1) {
- if (port1)
- buf[1] |= cOutputPort1Inactive;
- else
- buf[1] &= ~cOutputPort1Inactive;
- }
- if (UNSET != port2) {
- if (port2)
- buf[1] |= cOutputPort2Inactive;
- else
- buf[1] &= ~cOutputPort2Inactive;
- }
-
- if (UNSET != qss) {
- if (qss)
- buf[1] |= cQSS;
- else
- buf[1] &= ~cQSS;
- }
-
- if (adjust >= 0x00 && adjust < 0x20) {
- buf[2] &= ~cTopMask;
- buf[2] |= adjust;
- }
- return 0;
-}
-
-static int tda9887_do_config(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
- char *buf = priv->data;
-
- if (priv->config & TDA9887_PORT1_ACTIVE)
- buf[1] &= ~cOutputPort1Inactive;
- if (priv->config & TDA9887_PORT1_INACTIVE)
- buf[1] |= cOutputPort1Inactive;
- if (priv->config & TDA9887_PORT2_ACTIVE)
- buf[1] &= ~cOutputPort2Inactive;
- if (priv->config & TDA9887_PORT2_INACTIVE)
- buf[1] |= cOutputPort2Inactive;
-
- if (priv->config & TDA9887_QSS)
- buf[1] |= cQSS;
- if (priv->config & TDA9887_INTERCARRIER)
- buf[1] &= ~cQSS;
-
- if (priv->config & TDA9887_AUTOMUTE)
- buf[1] |= cAutoMuteFmActive;
- if (priv->config & TDA9887_DEEMPHASIS_MASK) {
- buf[2] &= ~0x60;
- switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
- case TDA9887_DEEMPHASIS_NONE:
- buf[2] |= cDeemphasisOFF;
- break;
- case TDA9887_DEEMPHASIS_50:
- buf[2] |= cDeemphasisON | cDeemphasis50;
- break;
- case TDA9887_DEEMPHASIS_75:
- buf[2] |= cDeemphasisON | cDeemphasis75;
- break;
- }
- }
- if (priv->config & TDA9887_TOP_SET) {
- buf[2] &= ~cTopMask;
- buf[2] |= (priv->config >> 8) & cTopMask;
- }
- if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
- (priv->std & V4L2_STD_NTSC))
- buf[1] &= ~cQSS;
- if (priv->config & TDA9887_GATING_18)
- buf[3] &= ~cGating_36;
-
- if (priv->mode == V4L2_TUNER_RADIO) {
- if (priv->config & TDA9887_RIF_41_3) {
- buf[3] &= ~cVideoIFMask;
- buf[3] |= cRadioIF_41_30;
- }
- if (priv->config & TDA9887_GAIN_NORMAL)
- buf[3] &= ~cTunerGainLow;
- }
-
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int tda9887_status(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
- unsigned char buf[1];
- int rc;
-
- memset(buf,0,sizeof(buf));
- if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
- tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
- dump_read_message(fe, buf);
- return 0;
-}
-
-static void tda9887_configure(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
- int rc;
-
- memset(priv->data,0,sizeof(priv->data));
- tda9887_set_tvnorm(fe);
-
- /* A note on the port settings:
- These settings tend to depend on the specifics of the board.
- By default they are set to inactive (bit value 1) by this driver,
- overwriting any changes made by the tvnorm. This means that it
- is the responsibility of the module using the tda9887 to set
- these values in case of changes in the tvnorm.
- In many cases port 2 should be made active (0) when selecting
- SECAM-L, and port 2 should remain inactive (1) for SECAM-L'.
-
- For the other standards the tda9887 application note says that
- the ports should be set to active (0), but, again, that may
- differ depending on the precise hardware configuration.
- */
- priv->data[1] |= cOutputPort1Inactive;
- priv->data[1] |= cOutputPort2Inactive;
-
- tda9887_do_config(fe);
- tda9887_set_insmod(fe);
-
- if (priv->mode == T_STANDBY)
- priv->data[1] |= cForcedMuteAudioON;
-
- tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
- priv->data[1], priv->data[2], priv->data[3]);
- if (debug > 1)
- dump_write_message(fe, priv->data);
-
- if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
- tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
-
- if (debug > 2) {
- msleep_interruptible(1000);
- tda9887_status(fe);
- }
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void tda9887_tuner_status(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
- tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
- priv->data[1], priv->data[2], priv->data[3]);
-}
-
-static int tda9887_get_afc(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
- static int AFC_BITS_2_kHz[] = {
- -12500, -37500, -62500, -97500,
- -112500, -137500, -162500, -187500,
- 187500, 162500, 137500, 112500,
- 97500 , 62500, 37500 , 12500
- };
- int afc=0;
- __u8 reg = 0;
-
- if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
- afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
-
- return afc;
-}
-
-static void tda9887_standby(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
-
- priv->mode = T_STANDBY;
-
- tda9887_configure(fe);
-}
-
-static void tda9887_set_params(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
-
- priv->mode = params->mode;
- priv->audmode = params->audmode;
- priv->std = params->std;
- tda9887_configure(fe);
-}
-
-static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
-
- priv->config = *(unsigned int *)priv_cfg;
- tda9887_configure(fe);
-
- return 0;
-}
-
-static void tda9887_release(struct dvb_frontend *fe)
-{
- struct tda9887_priv *priv = fe->analog_demod_priv;
-
- mutex_lock(&tda9887_list_mutex);
-
- if (priv)
- hybrid_tuner_release_state(priv);
-
- mutex_unlock(&tda9887_list_mutex);
-
- fe->analog_demod_priv = NULL;
-}
-
-static struct analog_demod_ops tda9887_ops = {
- .info = {
- .name = "tda9887",
- },
- .set_params = tda9887_set_params,
- .standby = tda9887_standby,
- .tuner_status = tda9887_tuner_status,
- .get_afc = tda9887_get_afc,
- .release = tda9887_release,
- .set_config = tda9887_set_config,
-};
-
-struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr)
-{
- struct tda9887_priv *priv = NULL;
- int instance;
-
- mutex_lock(&tda9887_list_mutex);
-
- instance = hybrid_tuner_request_state(struct tda9887_priv, priv,
- hybrid_tuner_instance_list,
- i2c_adap, i2c_addr, "tda9887");
- switch (instance) {
- case 0:
- mutex_unlock(&tda9887_list_mutex);
- return NULL;
- break;
- case 1:
- fe->analog_demod_priv = priv;
- priv->mode = T_STANDBY;
- tuner_info("tda988[5/6/7] found\n");
- break;
- default:
- fe->analog_demod_priv = priv;
- break;
- }
-
- mutex_unlock(&tda9887_list_mutex);
-
- memcpy(&fe->ops.analog_ops, &tda9887_ops,
- sizeof(struct analog_demod_ops));
-
- return fe;
-}
-EXPORT_SYMBOL_GPL(tda9887_attach);
-
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/linux/drivers/media/video/tda9887.h b/linux/drivers/media/video/tda9887.h
deleted file mode 100644
index 8f873a8e6..000000000
--- a/linux/drivers/media/video/tda9887.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TDA9887_H__
-#define __TDA9887_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-/* ------------------------------------------------------------------------ */
-#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE))
-extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr);
-#else
-static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- return NULL;
-}
-#endif
-
-#endif /* __TDA9887_H__ */
diff --git a/linux/drivers/media/video/tea5761.c b/linux/drivers/media/video/tea5761.c
deleted file mode 100644
index fa1d12d6f..000000000
--- a/linux/drivers/media/video/tea5761.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * For Philips TEA5761 FM Chip
- * I2C address is allways 0x20 (0x10 at 7-bit mode).
- *
- * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
- * This code is placed under the terms of the GNUv2 General Public License
- *
- */
-
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include "compat.h"
-#include <linux/videodev.h>
-#include <media/tuner.h>
-#include "tuner-i2c.h"
-#include "tea5761.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-struct tea5761_priv {
- struct tuner_i2c_props i2c_props;
-
- u32 frequency;
-};
-
-/*****************************************************************************/
-
-/***************************
- * TEA5761HN I2C registers *
- ***************************/
-
-/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
-
- /* first byte for reading */
-#define TEA5761_INTREG_IFFLAG 0x10
-#define TEA5761_INTREG_LEVFLAG 0x8
-#define TEA5761_INTREG_FRRFLAG 0x2
-#define TEA5761_INTREG_BLFLAG 0x1
-
- /* second byte for reading / byte for writing */
-#define TEA5761_INTREG_IFMSK 0x10
-#define TEA5761_INTREG_LEVMSK 0x8
-#define TEA5761_INTREG_FRMSK 0x2
-#define TEA5761_INTREG_BLMSK 0x1
-
-/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
-
- /* First byte */
-#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */
-#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */
-
- /* Bits 0-5 for divider MSB */
-
- /* Second byte */
- /* Bits 0-7 for divider LSB */
-
-/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
-
- /* first byte */
-
-#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */
-#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */
-#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */
-#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
-#define TEA5761_TNCTRL_AFM 0x04
-#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */
-#define TEA5761_TNCTRL_SNC 0x01
-
- /* second byte */
-
-#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */
-#define TEA5761_TNCTRL_SSL_1 0x40
-#define TEA5761_TNCTRL_SSL_0 0x20
-#define TEA5761_TNCTRL_HLSI 0x10
-#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */
-#define TEA5761_TNCTRL_SWP 0x04
-#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
-#define TEA5761_TNCTRL_AHLSI 0x01
-
-/* FRQCHECK - Read: bytes 6 and 7 */
- /* First byte */
-
- /* Bits 0-5 for divider MSB */
-
- /* Second byte */
- /* Bits 0-7 for divider LSB */
-
-/* TUNCHECK - Read: bytes 8 and 9 */
-
- /* First byte */
-#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */
-#define TEA5761_TUNCHECK_TUNTO 0x01
-
- /* Second byte */
-#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */
-#define TEA5761_TUNCHECK_LD 0x08
-#define TEA5761_TUNCHECK_STEREO 0x04
-
-/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
-
- /* All zero = no test mode */
-
-/* MANID - Read: bytes 12 and 13 */
-
- /* First byte - should be 0x10 */
-#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */
-#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */
-
- /* Second byte - Should be 0x2b */
-
-#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */
-#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */
-
-/* Chip ID - Read: bytes 14 and 15 */
-
- /* First byte - should be 0x57 */
-
- /* Second byte - should be 0x61 */
-
-/*****************************************************************************/
-
-#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
-static void tea5761_status_dump(unsigned char *buffer)
-{
- unsigned int div, frq;
-
- div = ((buffer[2] & 0x3f) << 8) | buffer[3];
-
- frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */
-
- printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n",
- frq / 1000, frq % 1000, div);
-}
-
-/* Freq should be specifyed at 62.5 Hz */
-static int set_radio_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tea5761_priv *priv = fe->tuner_priv;
- unsigned int frq = params->frequency;
- unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
- unsigned div;
- int rc;
-
- tuner_dbg("radio freq counter %d\n", frq);
-
- if (params->mode == T_STANDBY) {
- tuner_dbg("TEA5761 set to standby mode\n");
- buffer[5] |= TEA5761_TNCTRL_MU;
- } else {
- buffer[4] |= TEA5761_TNCTRL_PUPD_0;
- }
-
-
- if (params->audmode == V4L2_TUNER_MODE_MONO) {
- tuner_dbg("TEA5761 set to mono\n");
- buffer[5] |= TEA5761_TNCTRL_MST;
- } else {
- tuner_dbg("TEA5761 set to stereo\n");
- }
-
- div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
- buffer[1] = (div >> 8) & 0x3f;
- buffer[2] = div & 0xff;
-
- if (debug)
- tea5761_status_dump(buffer);
-
- if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7)))
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
-
- priv->frequency = frq * 125 / 2;
-
- return 0;
-}
-
-static int tea5761_read_status(struct dvb_frontend *fe, char *buffer)
-{
- struct tea5761_priv *priv = fe->tuner_priv;
- int rc;
-
- memset(buffer, 0, 16);
- if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) {
- tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc);
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer)
-{
- struct tea5761_priv *priv = fe->tuner_priv;
-
- int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
-
- tuner_dbg("Signal strength: %d\n", signal);
-
- return signal;
-}
-
-static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer)
-{
- struct tea5761_priv *priv = fe->tuner_priv;
-
- int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO;
-
- tuner_dbg("Radio ST GET = %02x\n", stereo);
-
- return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
-}
-
-static int tea5761_get_status(struct dvb_frontend *fe, u32 *status)
-{
- unsigned char buffer[16];
-
- *status = 0;
-
- if (0 == tea5761_read_status(fe, buffer)) {
- if (tea5761_signal(fe, buffer))
- *status = TUNER_STATUS_LOCKED;
- if (tea5761_stereo(fe, buffer))
- *status |= TUNER_STATUS_STEREO;
- }
-
- return 0;
-}
-
-static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
- unsigned char buffer[16];
-
- *strength = 0;
-
- if (0 == tea5761_read_status(fe, buffer))
- *strength = tea5761_signal(fe, buffer);
-
- return 0;
-}
-
-int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
-{
- unsigned char buffer[16];
- int rc;
- struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
-
- if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) {
- printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc);
- return EINVAL;
- }
-
- if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
- printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
- return EINVAL;
- }
- printk(KERN_WARNING "TEA5761 detected.\n");
- return 0;
-}
-
-static int tea5761_release(struct dvb_frontend *fe)
-{
- kfree(fe->tuner_priv);
- fe->tuner_priv = NULL;
-
- return 0;
-}
-
-static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct tea5761_priv *priv = fe->tuner_priv;
- *frequency = priv->frequency;
- return 0;
-}
-
-static struct dvb_tuner_ops tea5761_tuner_ops = {
- .info = {
- .name = "tea5761", // Philips TEA5761HN FM Radio
-#if 0
- .frequency_min = ,
- .frequency_max = ,
- .frequency_step = ,
-#endif
- },
- .set_analog_params = set_radio_freq,
- .release = tea5761_release,
- .get_frequency = tea5761_get_frequency,
- .get_status = tea5761_get_status,
- .get_rf_strength = tea5761_get_rf_strength,
-};
-
-struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr)
-{
- struct tea5761_priv *priv = NULL;
-
- if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL)
- return NULL;
-
- priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
- fe->tuner_priv = priv;
-
- priv->i2c_props.addr = i2c_addr;
- priv->i2c_props.adap = i2c_adap;
- priv->i2c_props.name = "tea5761";
-
- memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio");
-
- return fe;
-}
-
-
-EXPORT_SYMBOL_GPL(tea5761_attach);
-EXPORT_SYMBOL_GPL(tea5761_autodetection);
-
-MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/tea5761.h b/linux/drivers/media/video/tea5761.h
deleted file mode 100644
index 73a03b427..000000000
--- a/linux/drivers/media/video/tea5761.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TEA5761_H__
-#define __TEA5761_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
-extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
-
-extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr);
-#else
-static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap,
- u8 i2c_addr)
-{
- printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
- __FUNCTION__);
- return -EINVAL;
-}
-
-static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- return NULL;
-}
-#endif
-
-#endif /* __TEA5761_H__ */
diff --git a/linux/drivers/media/video/tea5767.c b/linux/drivers/media/video/tea5767.c
deleted file mode 100644
index c4f39a5d3..000000000
--- a/linux/drivers/media/video/tea5767.c
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview
- * I2C address is allways 0xC0.
- *
- *
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org)
- * This code is placed under the terms of the GNU General Public License
- *
- * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
- * from their contributions on DScaler.
- */
-
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include "compat.h"
-#include <linux/videodev.h>
-#include "tuner-i2c.h"
-#include "tea5767.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-/*****************************************************************************/
-
-struct tea5767_priv {
- struct tuner_i2c_props i2c_props;
- u32 frequency;
- struct tea5767_ctrl ctrl;
-};
-
-/*****************************************************************************/
-
-/******************************
- * Write mode register values *
- ******************************/
-
-/* First register */
-#define TEA5767_MUTE 0x80 /* Mutes output */
-#define TEA5767_SEARCH 0x40 /* Activates station search */
-/* Bits 0-5 for divider MSB */
-
-/* Second register */
-/* Bits 0-7 for divider LSB */
-
-/* Third register */
-
-/* Station search from botton to up */
-#define TEA5767_SEARCH_UP 0x80
-
-/* Searches with ADC output = 10 */
-#define TEA5767_SRCH_HIGH_LVL 0x60
-
-/* Searches with ADC output = 10 */
-#define TEA5767_SRCH_MID_LVL 0x40
-
-/* Searches with ADC output = 5 */
-#define TEA5767_SRCH_LOW_LVL 0x20
-
-/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */
-#define TEA5767_HIGH_LO_INJECT 0x10
-
-/* Disable stereo */
-#define TEA5767_MONO 0x08
-
-/* Disable right channel and turns to mono */
-#define TEA5767_MUTE_RIGHT 0x04
-
-/* Disable left channel and turns to mono */
-#define TEA5767_MUTE_LEFT 0x02
-
-#define TEA5767_PORT1_HIGH 0x01
-
-/* Fourth register */
-#define TEA5767_PORT2_HIGH 0x80
-/* Chips stops working. Only I2C bus remains on */
-#define TEA5767_STDBY 0x40
-
-/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */
-#define TEA5767_JAPAN_BAND 0x20
-
-/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */
-#define TEA5767_XTAL_32768 0x10
-
-/* Cuts weak signals */
-#define TEA5767_SOFT_MUTE 0x08
-
-/* Activates high cut control */
-#define TEA5767_HIGH_CUT_CTRL 0x04
-
-/* Activates stereo noise control */
-#define TEA5767_ST_NOISE_CTL 0x02
-
-/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */
-#define TEA5767_SRCH_IND 0x01
-
-/* Fifth register */
-
-/* By activating, it will use Xtal at 13 MHz as reference for divider */
-#define TEA5767_PLLREF_ENABLE 0x80
-
-/* By activating, deemphasis=50, or else, deemphasis of 50us */
-#define TEA5767_DEEMPH_75 0X40
-
-/*****************************
- * Read mode register values *
- *****************************/
-
-/* First register */
-#define TEA5767_READY_FLAG_MASK 0x80
-#define TEA5767_BAND_LIMIT_MASK 0X40
-/* Bits 0-5 for divider MSB after search or preset */
-
-/* Second register */
-/* Bits 0-7 for divider LSB after search or preset */
-
-/* Third register */
-#define TEA5767_STEREO_MASK 0x80
-#define TEA5767_IF_CNTR_MASK 0x7f
-
-/* Fourth register */
-#define TEA5767_ADC_LEVEL_MASK 0xf0
-
-/* should be 0 */
-#define TEA5767_CHIP_ID_MASK 0x0f
-
-/* Fifth register */
-/* Reserved for future extensions */
-#define TEA5767_RESERVED_MASK 0xff
-
-/*****************************************************************************/
-
-static void tea5767_status_dump(struct tea5767_priv *priv,
- unsigned char *buffer)
-{
- unsigned int div, frq;
-
- if (TEA5767_READY_FLAG_MASK & buffer[0])
- tuner_info("Ready Flag ON\n");
- else
- tuner_info("Ready Flag OFF\n");
-
- if (TEA5767_BAND_LIMIT_MASK & buffer[0])
- tuner_info("Tuner at band limit\n");
- else
- tuner_info("Tuner not at band limit\n");
-
- div = ((buffer[0] & 0x3f) << 8) | buffer[1];
-
- switch (priv->ctrl.xtal_freq) {
- case TEA5767_HIGH_LO_13MHz:
- frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */
- break;
- case TEA5767_LOW_LO_13MHz:
- frq = (div * 50000 + 700000 + 225000) / 4; /* Freq in KHz */
- break;
- case TEA5767_LOW_LO_32768:
- frq = (div * 32768 + 700000 + 225000) / 4; /* Freq in KHz */
- break;
- case TEA5767_HIGH_LO_32768:
- default:
- frq = (div * 32768 - 700000 - 225000) / 4; /* Freq in KHz */
- break;
- }
- buffer[0] = (div >> 8) & 0x3f;
- buffer[1] = div & 0xff;
-
- tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n",
- frq / 1000, frq % 1000, div);
-
- if (TEA5767_STEREO_MASK & buffer[2])
- tuner_info("Stereo\n");
- else
- tuner_info("Mono\n");
-
- tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK);
-
- tuner_info("ADC Level = %d\n",
- (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4);
-
- tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK));
-
- tuner_info("Reserved = 0x%02x\n",
- (buffer[4] & TEA5767_RESERVED_MASK));
-}
-
-/* Freq should be specifyed at 62.5 Hz */
-static int set_radio_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tea5767_priv *priv = fe->tuner_priv;
- unsigned int frq = params->frequency;
- unsigned char buffer[5];
- unsigned div;
- int rc;
-
- tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
-
- buffer[2] = 0;
-
- if (priv->ctrl.port1)
- buffer[2] |= TEA5767_PORT1_HIGH;
-
- if (params->audmode == V4L2_TUNER_MODE_MONO) {
- tuner_dbg("TEA5767 set to mono\n");
- buffer[2] |= TEA5767_MONO;
- } else {
- tuner_dbg("TEA5767 set to stereo\n");
- }
-
-
- buffer[3] = 0;
-
- if (priv->ctrl.port2)
- buffer[3] |= TEA5767_PORT2_HIGH;
-
- if (priv->ctrl.high_cut)
- buffer[3] |= TEA5767_HIGH_CUT_CTRL;
-
- if (priv->ctrl.st_noise)
- buffer[3] |= TEA5767_ST_NOISE_CTL;
-
- if (priv->ctrl.soft_mute)
- buffer[3] |= TEA5767_SOFT_MUTE;
-
- if (priv->ctrl.japan_band)
- buffer[3] |= TEA5767_JAPAN_BAND;
-
- buffer[4] = 0;
-
- if (priv->ctrl.deemph_75)
- buffer[4] |= TEA5767_DEEMPH_75;
-
- if (priv->ctrl.pllref)
- buffer[4] |= TEA5767_PLLREF_ENABLE;
-
-
- /* Rounds freq to next decimal value - for 62.5 KHz step */
- /* frq = 20*(frq/16)+radio_frq[frq%16]; */
-
- switch (priv->ctrl.xtal_freq) {
- case TEA5767_HIGH_LO_13MHz:
- tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
- buffer[2] |= TEA5767_HIGH_LO_INJECT;
- div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
- break;
- case TEA5767_LOW_LO_13MHz:
- tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
-
- div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
- break;
- case TEA5767_LOW_LO_32768:
- tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n");
- buffer[3] |= TEA5767_XTAL_32768;
- /* const 700=4000*175 Khz - to adjust freq to right value */
- div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15;
- break;
- case TEA5767_HIGH_LO_32768:
- default:
- tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n");
-
- buffer[2] |= TEA5767_HIGH_LO_INJECT;
- buffer[3] |= TEA5767_XTAL_32768;
- div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15;
- break;
- }
- buffer[0] = (div >> 8) & 0x3f;
- buffer[1] = div & 0xff;
-
- if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
-
- if (debug) {
- if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
- else
- tea5767_status_dump(priv, buffer);
- }
-
- priv->frequency = frq * 125 / 2;
-
- return 0;
-}
-
-static int tea5767_read_status(struct dvb_frontend *fe, char *buffer)
-{
- struct tea5767_priv *priv = fe->tuner_priv;
- int rc;
-
- memset(buffer, 0, 5);
- if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) {
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer)
-{
- struct tea5767_priv *priv = fe->tuner_priv;
-
- int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
-
- tuner_dbg("Signal strength: %d\n", signal);
-
- return signal;
-}
-
-static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer)
-{
- struct tea5767_priv *priv = fe->tuner_priv;
-
- int stereo = buffer[2] & TEA5767_STEREO_MASK;
-
- tuner_dbg("Radio ST GET = %02x\n", stereo);
-
- return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
-}
-
-static int tea5767_get_status(struct dvb_frontend *fe, u32 *status)
-{
- unsigned char buffer[5];
-
- *status = 0;
-
- if (0 == tea5767_read_status(fe, buffer)) {
- if (tea5767_signal(fe, buffer))
- *status = TUNER_STATUS_LOCKED;
- if (tea5767_stereo(fe, buffer))
- *status |= TUNER_STATUS_STEREO;
- }
-
- return 0;
-}
-
-static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
- unsigned char buffer[5];
-
- *strength = 0;
-
- if (0 == tea5767_read_status(fe, buffer))
- *strength = tea5767_signal(fe, buffer);
-
- return 0;
-}
-
-static int tea5767_standby(struct dvb_frontend *fe)
-{
- unsigned char buffer[5];
- struct tea5767_priv *priv = fe->tuner_priv;
- unsigned div, rc;
-
- div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */
- buffer[0] = (div >> 8) & 0x3f;
- buffer[1] = div & 0xff;
- buffer[2] = TEA5767_PORT1_HIGH;
- buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
- TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY;
- buffer[4] = 0;
-
- if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
-
- return 0;
-}
-
-int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
-{
- struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
- unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- int rc;
-#if 0 /* Needed if uncomment I2C send code below */
- int div;
-#endif
-
- if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) {
- printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc);
- return EINVAL;
- }
-
- /* If all bytes are the same then it's a TV tuner and not a tea5767 */
- if (buffer[0] == buffer[1] && buffer[0] == buffer[2] &&
- buffer[0] == buffer[3] && buffer[0] == buffer[4]) {
- printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n");
- return EINVAL;
- }
-
- /* Status bytes:
- * Byte 4: bit 3:1 : CI (Chip Identification) == 0
- * bit 0 : internally set to 0
- * Byte 5: bit 7:0 : == 0
- */
- if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) {
- printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n");
- return EINVAL;
- }
-
- /* It seems that tea5767 returns 0xff after the 5th byte */
- if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) {
- printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n");
- return EINVAL;
- }
-
-#if 0 /*Sometimes, this code doesn't work */
- /* Sets tuner at some freq (87.5 MHz) and see if it is ok */
- div = ((87500 * 4000 + 700000 + 225000) + 16768) >> 15;
- buffer[0] = ((div >> 8) & 0x3f) | TEA5767_MUTE;
- buffer[1] = div & 0xff;
- buffer[2] = TEA5767_PORT1_HIGH;
- buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
- TEA5767_ST_NOISE_CTL;
- buffer[4] = 0;
-
- if (5 != (rc = tuner_i2c_xfer_send(&i2c, buffer, 5)))
- printk(KERN_WARNING "i2c i/o error: rc == %d (should be 5)\n", rc);
-
- msleep(15);
-
- if (5 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 5))) {
- printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc);
- return EINVAL;
- }
-
- /* Initial freq for 32.768KHz clock */
- if ((buffer[1] != (div & 0xff) ) || ((buffer[0] & 0x3f) != ((div >> 8) & 0x3f))) {
- printk(KERN_WARNING "It is not a TEA5767. div=%d, Return: %02x %02x %02x %02x %02x\n",
- div,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4]);
- tea5767_status_dump(buffer);
- return EINVAL;
- }
-#endif
- return 0;
-}
-
-static int tea5767_release(struct dvb_frontend *fe)
-{
- kfree(fe->tuner_priv);
- fe->tuner_priv = NULL;
-
- return 0;
-}
-
-static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct tea5767_priv *priv = fe->tuner_priv;
- *frequency = priv->frequency;
-
- return 0;
-}
-
-static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg)
-{
- struct tea5767_priv *priv = fe->tuner_priv;
-
- memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl));
-
- return 0;
-}
-
-static struct dvb_tuner_ops tea5767_tuner_ops = {
- .info = {
- .name = "tea5767", // Philips TEA5767HN FM Radio
-#if 0
- .frequency_min = ,
- .frequency_max = ,
- .frequency_step = ,
-#endif
- },
-
- .set_analog_params = set_radio_freq,
- .set_config = tea5767_set_config,
- .sleep = tea5767_standby,
- .release = tea5767_release,
- .get_frequency = tea5767_get_frequency,
- .get_status = tea5767_get_status,
- .get_rf_strength = tea5767_get_rf_strength,
-};
-
-struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr)
-{
- struct tea5767_priv *priv = NULL;
-
-#if 0 /* By removing autodetection allows forcing TEA chip */
- if (tea5767_autodetection(i2c_adap, i2c_addr) == EINVAL)
- return EINVAL;
-#endif
- priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
- fe->tuner_priv = priv;
-
- priv->i2c_props.addr = i2c_addr;
- priv->i2c_props.adap = i2c_adap;
- priv->i2c_props.name = "tea5767";
-
- priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768;
- priv->ctrl.port1 = 1;
- priv->ctrl.port2 = 1;
- priv->ctrl.high_cut = 1;
- priv->ctrl.st_noise = 1;
- priv->ctrl.japan_band = 1;
-
- memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio");
-
- return fe;
-}
-
-EXPORT_SYMBOL_GPL(tea5767_attach);
-EXPORT_SYMBOL_GPL(tea5767_autodetection);
-
-MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/tea5767.h b/linux/drivers/media/video/tea5767.h
deleted file mode 100644
index a44451f61..000000000
--- a/linux/drivers/media/video/tea5767.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TEA5767_H__
-#define __TEA5767_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-enum tea5767_xtal {
- TEA5767_LOW_LO_32768 = 0,
- TEA5767_HIGH_LO_32768 = 1,
- TEA5767_LOW_LO_13MHz = 2,
- TEA5767_HIGH_LO_13MHz = 3,
-};
-
-struct tea5767_ctrl {
- unsigned int port1:1;
- unsigned int port2:1;
- unsigned int high_cut:1;
- unsigned int st_noise:1;
- unsigned int soft_mute:1;
- unsigned int japan_band:1;
- unsigned int deemph_75:1;
- unsigned int pllref:1;
- enum tea5767_xtal xtal_freq;
-};
-
-#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
-extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
-
-extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr);
-#else
-static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap,
- u8 i2c_addr)
-{
- printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
- __FUNCTION__);
- return -EINVAL;
-}
-
-static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
- struct i2c_adapter* i2c_adap,
- u8 i2c_addr)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- return NULL;
-}
-#endif
-
-#endif /* __TEA5767_H__ */
diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c
index 003fe1edb..16f369195 100644
--- a/linux/drivers/media/video/tea6415c.c
+++ b/linux/drivers/media/video/tea6415c.c
@@ -39,10 +39,10 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __func__, __LINE__); printk(args); } } while (0)
#else
#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
#endif
#define TEA6415C_NUM_INPUTS 8
@@ -73,7 +73,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind)
/* allocate memory for client structure */
client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (0 == client) {
+ if (!client) {
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c
index 261675012..7a8fec9cf 100644
--- a/linux/drivers/media/video/tea6420.c
+++ b/linux/drivers/media/video/tea6420.c
@@ -39,10 +39,10 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ",__stringify(KBUILD_MODNAME), __func__, __LINE__); printk(args); } } while (0)
#else
#define dprintk(args...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
#endif
/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
@@ -110,7 +110,7 @@ static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind)
/* allocate memory for client structure */
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (0 == client) {
+ if (!client) {
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/tlv320aic23b.c b/linux/drivers/media/video/tlv320aic23b.c
index 29e1f8a7b..9f96e200c 100644
--- a/linux/drivers/media/video/tlv320aic23b.c
+++ b/linux/drivers/media/video/tlv320aic23b.c
@@ -133,7 +133,8 @@ static int tlv320aic23b_command(struct i2c_client *client,
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int tlv320aic23b_probe(struct i2c_client *client)
+static int tlv320aic23b_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tlv320aic23b_state *state;
@@ -174,15 +175,25 @@ static int tlv320aic23b_remove(struct i2c_client *client)
}
/* ----------------------------------------------------------------------- */
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
EXPORT_NO_SYMBOLS;
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id tlv320aic23b_id[] = {
+ { "tlv320aic23b", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tlv320aic23b",
.driverid = I2C_DRIVERID_TLV320AIC23B,
.command = tlv320aic23b_command,
.probe = tlv320aic23b_probe,
.remove = tlv320aic23b_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tlv320aic23b_id,
+#endif
};
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index 38a90afb6..e0228b865 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -41,6 +41,46 @@
#define PREFIX t->i2c->driver->driver.name
#endif
+/** This macro allows us to probe dynamically, avoiding static links */
+#ifdef CONFIG_MEDIA_ATTACH
+#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
+ int __r = -EINVAL; \
+ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+ if (__a) { \
+ __r = (int) __a(ARGS); \
+ symbol_put(FUNCTION); \
+ } else { \
+ printk(KERN_ERR "TUNER: Unable to find " \
+ "symbol "#FUNCTION"()\n"); \
+ } \
+ __r; \
+})
+
+static void tuner_detach(struct dvb_frontend *fe)
+{
+ if (fe->ops.tuner_ops.release) {
+ fe->ops.tuner_ops.release(fe);
+ symbol_put_addr(fe->ops.tuner_ops.release);
+ }
+ if (fe->ops.analog_ops.release) {
+ fe->ops.analog_ops.release(fe);
+ symbol_put_addr(fe->ops.analog_ops.release);
+ }
+}
+#else
+#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
+ FUNCTION(ARGS); \
+})
+
+static void tuner_detach(struct dvb_frontend *fe)
+{
+ if (fe->ops.tuner_ops.release)
+ fe->ops.tuner_ops.release(fe);
+ if (fe->ops.analog_ops.release)
+ fe->ops.analog_ops.release(fe);
+}
+#endif
+
struct tuner {
/* device */
struct dvb_frontend fe;
@@ -60,11 +100,12 @@ struct tuner {
unsigned int type; /* chip type id */
unsigned int config;
int (*tuner_callback) (void *dev, int command, int arg);
+ const char *name;
};
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
-#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
0x10,
#endif
0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
@@ -168,22 +209,6 @@ static void fe_set_params(struct dvb_frontend *fe,
fe_tuner_ops->set_analog_params(fe, params);
}
-static void fe_release(struct dvb_frontend *fe)
-{
- if (fe->ops.tuner_ops.release)
- fe->ops.tuner_ops.release(fe);
-
- /* DO NOT kfree(fe->analog_demod_priv)
- *
- * If we are in this function, analog_demod_priv contains a pointer
- * to struct tuner *t. This will be kfree'd in tuner_detach().
- *
- * Otherwise, fe->ops.analog_demod_ops->release will
- * handle the cleanup for analog demodulator modules.
- */
- fe->analog_demod_priv = NULL;
-}
-
static void fe_standby(struct dvb_frontend *fe)
{
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
@@ -220,7 +245,6 @@ static void tuner_status(struct dvb_frontend *fe);
static struct analog_demod_ops tuner_core_ops = {
.set_params = fe_set_params,
.standby = fe_standby,
- .release = fe_release,
.has_signal = fe_has_signal,
.set_config = fe_set_config,
.tuner_status = tuner_status
@@ -336,25 +360,16 @@ static void tuner_i2c_address_check(struct tuner *t)
tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
tuner_warn("will soon be dropped. This message indicates that your\n");
tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
- t->i2c->name, t->i2c->addr);
+ t->name, t->i2c->addr);
tuner_warn("To ensure continued support for your device, please\n");
tuner_warn("send a copy of this message, along with full dmesg\n");
tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
- t->i2c->adapter->name, t->i2c->addr, t->type, t->i2c->name);
+ t->i2c->adapter->name, t->i2c->addr, t->type, t->name);
tuner_warn("====================== WARNING! ======================\n");
}
-static void attach_tda829x(struct tuner *t)
-{
- struct tda829x_config cfg = {
- .lna_cfg = t->config,
- .tuner_callback = t->tuner_callback,
- };
- tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
-}
-
static struct xc5000_config xc5000_cfg;
static void set_type(struct i2c_client *c, unsigned int type,
@@ -385,32 +400,36 @@ static void set_type(struct i2c_client *c, unsigned int type,
}
/* discard private data, in case set_type() was previously called */
- if (analog_ops->release)
- analog_ops->release(&t->fe);
+ tuner_detach(&t->fe);
+ t->fe.analog_demod_priv = NULL;
switch (t->type) {
case TUNER_MT2032:
- microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+ if (!dvb_attach(microtune_attach,
+ &t->fe, t->i2c->adapter, t->i2c->addr))
+ goto attach_failed;
break;
case TUNER_PHILIPS_TDA8290:
{
- attach_tda829x(t);
+ struct tda829x_config cfg = {
+ .lna_cfg = t->config,
+ .tuner_callback = t->tuner_callback,
+ };
+ if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,
+ t->i2c->addr, &cfg))
+ goto attach_failed;
break;
}
case TUNER_TEA5767:
- if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!dvb_attach(tea5767_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr))
+ goto attach_failed;
t->mode_mask = T_RADIO;
break;
case TUNER_TEA5761:
- if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!dvb_attach(tea5761_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr))
+ goto attach_failed;
t->mode_mask = T_RADIO;
break;
case TUNER_PHILIPS_FMD1216ME_MK3:
@@ -423,25 +442,19 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0x54;
i2c_master_send(c, buffer, 4);
- if (simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
- t->type) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
+ goto attach_failed;
break;
case TUNER_PHILIPS_TD1316:
buffer[0] = 0x0b;
buffer[1] = 0xdc;
buffer[2] = 0x86;
buffer[3] = 0xa4;
- i2c_master_send(c,buffer,4);
- if (simple_tuner_attach(&t->fe, t->i2c->adapter,
- t->i2c->addr, t->type) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ i2c_master_send(c, buffer, 4);
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
+ goto attach_failed;
break;
case TUNER_XC2028:
{
@@ -450,62 +463,67 @@ static void set_type(struct i2c_client *c, unsigned int type,
.i2c_addr = t->i2c->addr,
.callback = t->tuner_callback,
};
- if (!xc2028_attach(&t->fe, &cfg)) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
+ goto attach_failed;
break;
}
case TUNER_TDA9887:
- tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+ if (!dvb_attach(tda9887_attach,
+ &t->fe, t->i2c->adapter, t->i2c->addr))
+ goto attach_failed;
break;
case TUNER_XC5000:
+ {
+ struct dvb_tuner_ops *xc_tuner_ops;
+
xc5000_cfg.i2c_address = t->i2c->addr;
xc5000_cfg.if_khz = 5380;
- xc5000_cfg.priv = c->adapter->algo_data;
xc5000_cfg.tuner_callback = t->tuner_callback;
- if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
- {
- struct dvb_tuner_ops *xc_tuner_ops;
+ if (!dvb_attach(xc5000_attach,
+ &t->fe, t->i2c->adapter, &xc5000_cfg,
+ c->adapter->algo_data))
+ goto attach_failed;
+
xc_tuner_ops = &t->fe.ops.tuner_ops;
- if(xc_tuner_ops->init != NULL)
+ if (xc_tuner_ops->init)
xc_tuner_ops->init(&t->fe);
- }
break;
+ }
default:
- if (simple_tuner_attach(&t->fe, t->i2c->adapter,
- t->i2c->addr, t->type) == NULL) {
- t->type = TUNER_ABSENT;
- t->mode_mask = T_UNINITIALIZED;
- return;
- }
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
+ goto attach_failed;
+
break;
}
if ((NULL == analog_ops->set_params) &&
(fe_tuner_ops->set_analog_params)) {
- strlcpy(t->i2c->name, fe_tuner_ops->info.name,
- sizeof(t->i2c->name));
+
+ t->name = fe_tuner_ops->info.name;
t->fe.analog_demod_priv = t;
memcpy(analog_ops, &tuner_core_ops,
sizeof(struct analog_demod_ops));
+
} else {
- strlcpy(t->i2c->name, analog_ops->info.name,
- sizeof(t->i2c->name));
+ t->name = analog_ops->info.name;
}
- tuner_dbg("type set to %s\n", t->i2c->name);
+ tuner_dbg("type set to %s\n", t->name);
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;
- set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
+ /* xc2028/3028 and xc5000 requires a firmware to be set-up later
+ trying to set a frequency here will just fail
+ FIXME: better to move set_freq to the tuner code. This is needed
+ on analog tuners for PLL to properly work
+ */
+ if (t->type != TUNER_XC2028 && t->type != TUNER_XC5000)
+ set_freq(c, (V4L2_TUNER_RADIO == t->mode) ?
+ t->radio_freq : t->tv_freq);
+
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
c->adapter->name, c->driver->name, c->addr << 1, type,
@@ -516,6 +534,14 @@ static void set_type(struct i2c_client *c, unsigned int type,
t->mode_mask);
#endif
tuner_i2c_address_check(t);
+ return;
+
+attach_failed:
+ tuner_dbg("Tuner attach for type = %d failed.\n", t->type);
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+
+ return;
}
/*
@@ -530,14 +556,16 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
struct tuner *t = i2c_get_clientdata(c);
- tuner_dbg("set addr for type %i\n", t->type);
-
if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
(t->mode_mask & tun_setup->mode_mask))) ||
(tun_setup->addr == c->addr)) {
set_type(c, tun_setup->type, tun_setup->mode_mask,
tun_setup->config, tun_setup->tuner_callback);
- }
+ } else
+ tuner_dbg("set addr discarded for type %i, mask %x. "
+ "Asked to change tuner at addr 0x%02x, with mask %x\n",
+ t->type, t->mode_mask,
+ tun_setup->addr, tun_setup->mode_mask);
}
static inline int check_mode(struct tuner *t, char *cmd)
@@ -546,7 +574,7 @@ static inline int check_mode(struct tuner *t, char *cmd)
#if 0
tuner_dbg("Cmd %s rejected for mode %i\n", cmd,t->mode);
#endif
- return EINVAL;
+ return -EINVAL;
}
switch (t->mode) {
@@ -683,8 +711,8 @@ static void tuner_status(struct dvb_frontend *fe)
{
struct tuner *t = fe->analog_demod_priv;
unsigned long freq, freq_fraction;
- struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
- struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+ struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
const char *p;
switch (t->mode) {
@@ -740,11 +768,11 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
t->mode = mode;
- if (check_mode(t, cmd) == EINVAL) {
+ if (check_mode(t, cmd) == -EINVAL) {
t->mode = T_STANDBY;
if (analog_ops->standby)
analog_ops->standby(&t->fe);
- return EINVAL;
+ return -EINVAL;
}
return 0;
}
@@ -774,8 +802,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (tuner_debug>1)
+ if (tuner_debug > 1) {
v4l_i2c_print_ioctl(client,cmd);
+ printk("\n");
+ }
switch (cmd) {
/* --- configuration --- */
@@ -790,23 +820,23 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
case AUDC_SET_RADIO:
if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
- == EINVAL)
+ == -EINVAL)
return 0;
if (t->radio_freq)
set_freq(client, t->radio_freq);
break;
case TUNER_SET_STANDBY:
- if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
+ if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
return 0;
t->mode = T_STANDBY;
if (analog_ops->standby)
analog_ops->standby(&t->fe);
break;
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
case VIDIOCSAUDIO:
- if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
+ if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL)
return 0;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
/* Should be implemented, since bttv calls it */
@@ -824,10 +854,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
};
struct video_channel *vc = arg;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
- if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
+ if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==-EINVAL)
return 0;
if (vc->norm < ARRAY_SIZE(map))
@@ -841,9 +871,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
unsigned long *v = arg;
- if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
+ if (check_mode(t, "VIDIOCSFREQ") == -EINVAL)
return 0;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
set_freq(client, *v);
@@ -853,9 +883,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_tuner *vt = arg;
- if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
+ if (check_mode(t, "VIDIOCGTUNER") == -EINVAL)
return 0;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
if (V4L2_TUNER_RADIO == t->mode) {
@@ -897,9 +927,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_audio *va = arg;
- if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
+ if (check_mode(t, "VIDIOCGAUDIO") == -EINVAL)
return 0;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
if (V4L2_TUNER_RADIO == t->mode) {
@@ -939,7 +969,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
v4l2_std_id *id = arg;
if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
- == EINVAL)
+ == -EINVAL)
return 0;
switch_v4l2();
@@ -955,7 +985,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
struct v4l2_frequency *f = arg;
if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
- == EINVAL)
+ == -EINVAL)
return 0;
switch_v4l2();
set_freq(client,f->frequency);
@@ -966,7 +996,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_frequency *f = arg;
- if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
+ if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
return 0;
switch_v4l2();
f->type = t->mode;
@@ -987,7 +1017,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *tuner = arg;
- if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
+ if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
return 0;
switch_v4l2();
@@ -1034,7 +1064,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *tuner = arg;
- if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
+ if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
return 0;
switch_v4l2();
@@ -1117,7 +1147,8 @@ static void tuner_lookup(struct i2c_adapter *adap,
/* During client attach, set_type is called by adapter's attach_inform callback.
set_type must then be completed by tuner_probe.
*/
-static int tuner_probe(struct i2c_client *client)
+static int tuner_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tuner *t;
struct tuner *radio;
@@ -1127,7 +1158,7 @@ static int tuner_probe(struct i2c_client *client)
if (NULL == t)
return -ENOMEM;
t->i2c = client;
- strlcpy(client->name, "(tuner unset)", sizeof(client->name));
+ t->name = "(tuner unset)";
i2c_set_clientdata(client, t);
t->type = UNSET;
t->audmode = V4L2_TUNER_MODE_STEREO;
@@ -1155,8 +1186,9 @@ static int tuner_probe(struct i2c_client *client)
if (!no_autodetect) {
switch (client->addr) {
case 0x10:
- if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
- != EINVAL) {
+ if (tuner_symbol_probe(tea5761_autodetection,
+ t->i2c->adapter,
+ t->i2c->addr) >= 0) {
t->type = TUNER_TEA5761;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -1168,15 +1200,15 @@ static int tuner_probe(struct i2c_client *client)
goto register_client;
}
- break;
+ return -ENODEV;
case 0x42:
case 0x43:
case 0x4a:
case 0x4b:
/* If chip is not tda8290, don't register.
since it can be tda9887*/
- if (tda829x_probe(t->i2c->adapter,
- t->i2c->addr) == 0) {
+ if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
+ t->i2c->addr) >= 0) {
tuner_dbg("tda829x detected\n");
} else {
/* Default is being tda9887 */
@@ -1188,8 +1220,9 @@ static int tuner_probe(struct i2c_client *client)
}
break;
case 0x60:
- if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
- != EINVAL) {
+ if (tuner_symbol_probe(tea5767_autodetection,
+ t->i2c->adapter, t->i2c->addr)
+ >= 0) {
t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -1281,10 +1314,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap)
static int tuner_remove(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
- struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (analog_ops->release)
- analog_ops->release(&t->fe);
+ tuner_detach(&t->fe);
+ t->fe.analog_demod_priv = NULL;
list_del(&t->list);
kfree(t);
@@ -1293,6 +1325,17 @@ static int tuner_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+/* This driver supports many devices and the idea is to let the driver
+ detect which device is present. So rather than listing all supported
+ devices here, we pretend to support a single, fake device type. */
+static const struct i2c_device_id tuner_id[] = {
+ { "tuner", }, /* autodetect */
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tuner_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tuner",
.driverid = I2C_DRIVERID_TUNER,
@@ -1302,6 +1345,9 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.suspend = tuner_suspend,
.resume = tuner_resume,
.legacy_probe = tuner_legacy_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = tuner_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/tuner-i2c.h b/linux/drivers/media/video/tuner-i2c.h
deleted file mode 100644
index 3ad6c8e0b..000000000
--- a/linux/drivers/media/video/tuner-i2c.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- tuner-i2c.h - i2c interface for different tuners
-
- Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TUNER_I2C_H__
-#define __TUNER_I2C_H__
-
-#include <linux/i2c.h>
-
-struct tuner_i2c_props {
- u8 addr;
- struct i2c_adapter *adap;
-
- /* used for tuner instance management */
- int count;
- char *name;
-};
-
-static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len)
-{
- struct i2c_msg msg = { .addr = props->addr, .flags = 0,
- .buf = buf, .len = len };
- int ret = i2c_transfer(props->adap, &msg, 1);
-
- return (ret == 1) ? len : ret;
-}
-
-static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len)
-{
- struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
- .buf = buf, .len = len };
- int ret = i2c_transfer(props->adap, &msg, 1);
-
- return (ret == 1) ? len : ret;
-}
-
-static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
- char *obuf, int olen,
- char *ibuf, int ilen)
-{
- struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
- .buf = obuf, .len = olen },
- { .addr = props->addr, .flags = I2C_M_RD,
- .buf = ibuf, .len = ilen } };
- int ret = i2c_transfer(props->adap, msg, 2);
-
- return (ret == 2) ? ilen : ret;
-}
-
-/* Callers must declare as a global for the module:
- *
- * static LIST_HEAD(hybrid_tuner_instance_list);
- *
- * hybrid_tuner_instance_list should be the third argument
- * passed into hybrid_tuner_request_state().
- *
- * state structure must contain the following:
- *
- * struct list_head hybrid_tuner_instance_list;
- * struct tuner_i2c_props i2c_props;
- *
- * hybrid_tuner_instance_list (both within state structure and globally)
- * is only required if the driver is using hybrid_tuner_request_state
- * and hybrid_tuner_release_state to manage state sharing between
- * multiple instances of hybrid tuners.
- */
-
-#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \
- printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \
- i2cprops.adap ? \
- i2c_adapter_id(i2cprops.adap) : -1, \
- i2cprops.addr, ##arg); \
- } while (0)
-
-/* TO DO: convert all callers of these macros to pass in
- * struct tuner_i2c_props, then remove the macro wrappers */
-
-#define __tuner_warn(i2cprops, fmt, arg...) do { \
- tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \
- } while (0)
-
-#define __tuner_info(i2cprops, fmt, arg...) do { \
- tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \
- } while (0)
-
-#define __tuner_err(i2cprops, fmt, arg...) do { \
- tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \
- } while (0)
-
-#define __tuner_dbg(i2cprops, fmt, arg...) do { \
- if ((debug)) \
- tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \
- } while (0)
-
-#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg)
-#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg)
-#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg)
-#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg)
-
-/****************************************************************************/
-
-/* The return value of hybrid_tuner_request_state indicates the number of
- * instances using this tuner object.
- *
- * 0 - no instances, indicates an error - kzalloc must have failed
- *
- * 1 - one instance, indicates that the tuner object was created successfully
- *
- * 2 (or more) instances, indicates that an existing tuner object was found
- */
-
-#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\
-({ \
- int __ret = 0; \
- list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \
- if (((i2cadap) && (state->i2c_props.adap)) && \
- ((i2c_adapter_id(state->i2c_props.adap) == \
- i2c_adapter_id(i2cadap)) && \
- (i2caddr == state->i2c_props.addr))) { \
- __tuner_info(state->i2c_props, \
- "attaching existing instance\n"); \
- state->i2c_props.count++; \
- __ret = state->i2c_props.count; \
- break; \
- } \
- } \
- if (0 == __ret) { \
- state = kzalloc(sizeof(type), GFP_KERNEL); \
- if (NULL == state) \
- goto __fail; \
- state->i2c_props.addr = i2caddr; \
- state->i2c_props.adap = i2cadap; \
- state->i2c_props.name = devname; \
- __tuner_info(state->i2c_props, \
- "creating new instance\n"); \
- list_add_tail(&state->hybrid_tuner_instance_list, &list);\
- state->i2c_props.count++; \
- __ret = state->i2c_props.count; \
- } \
-__fail: \
- __ret; \
-})
-
-#define hybrid_tuner_release_state(state) \
-({ \
- int __ret; \
- state->i2c_props.count--; \
- __ret = state->i2c_props.count; \
- if (!state->i2c_props.count) { \
- __tuner_info(state->i2c_props, "destroying instance\n");\
- list_del(&state->hybrid_tuner_instance_list); \
- kfree(state); \
- } \
- __ret; \
-})
-
-#endif /* __TUNER_I2C_H__ */
diff --git a/linux/drivers/media/video/tuner-simple.c b/linux/drivers/media/video/tuner-simple.c
deleted file mode 100644
index 772bfefbe..000000000
--- a/linux/drivers/media/video/tuner-simple.c
+++ /dev/null
@@ -1,1136 +0,0 @@
-/*
- * i2c tv tuner chip device driver
- * controls all those simple 4-control-bytes style tuners.
- *
- * This "tuner-simple" module was split apart from the original "tuner" module.
- */
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include "compat.h"
-#include <linux/videodev.h>
-#include <media/tuner.h>
-#include <media/v4l2-common.h>
-#include <media/tuner-types.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include "i2c-compat.h"
-#endif
-#include "tuner-i2c.h"
-#include "tuner-simple.h"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-#define TUNER_SIMPLE_MAX 64
-static unsigned int simple_devcount;
-
-static int offset;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(offset, "i");
-#else
-module_param(offset, int, 0664);
-#endif
-MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
-
-static unsigned int atv_input[TUNER_SIMPLE_MAX] = \
- { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
-static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
- { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
-module_param_array(atv_input, int, NULL, 0644);
-module_param_array(dtv_input, int, NULL, 0644);
-MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
-MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
-
-/* ---------------------------------------------------------------------- */
-
-/* tv standard selection for Temic 4046 FM5
- this value takes the low bits of control byte 2
- from datasheet Rev.01, Feb.00
- standard BG I L L2 D
- picture IF 38.9 38.9 38.9 33.95 38.9
- sound 1 33.4 32.9 32.4 40.45 32.4
- sound 2 33.16
- NICAM 33.05 32.348 33.05 33.05
- */
-#define TEMIC_SET_PAL_I 0x05
-#define TEMIC_SET_PAL_DK 0x09
-#define TEMIC_SET_PAL_L 0x0a /* SECAM ? */
-#define TEMIC_SET_PAL_L2 0x0b /* change IF ! */
-#define TEMIC_SET_PAL_BG 0x0c
-
-/* tv tuner system standard selection for Philips FQ1216ME
- this value takes the low bits of control byte 2
- from datasheet "1999 Nov 16" (supersedes "1999 Mar 23")
- standard BG DK I L L`
- picture carrier 38.90 38.90 38.90 38.90 33.95
- colour 34.47 34.47 34.47 34.47 38.38
- sound 1 33.40 32.40 32.90 32.40 40.45
- sound 2 33.16 - - - -
- NICAM 33.05 33.05 32.35 33.05 39.80
- */
-#define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/
-#define PHILIPS_SET_PAL_BGDK 0x09
-#define PHILIPS_SET_PAL_L2 0x0a
-#define PHILIPS_SET_PAL_L 0x0b
-
-/* system switching for Philips FI1216MF MK2
- from datasheet "1996 Jul 09",
- standard BG L L'
- picture carrier 38.90 38.90 33.95
- colour 34.47 34.37 38.38
- sound 1 33.40 32.40 40.45
- sound 2 33.16 - -
- NICAM 33.05 33.05 39.80
- */
-#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */
-#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */
-
-/* Control byte */
-
-#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */
-#define TUNER_RATIO_SELECT_50 0x00
-#define TUNER_RATIO_SELECT_32 0x02
-#define TUNER_RATIO_SELECT_166 0x04
-#define TUNER_RATIO_SELECT_62 0x06
-
-#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */
-
-/* Status byte */
-
-#define TUNER_POR 0x80
-#define TUNER_FL 0x40
-#define TUNER_MODE 0x38
-#define TUNER_AFC 0x07
-#define TUNER_SIGNAL 0x07
-#define TUNER_STEREO 0x10
-
-#define TUNER_PLL_LOCKED 0x40
-#define TUNER_STEREO_MK3 0x04
-
-static DEFINE_MUTEX(tuner_simple_list_mutex);
-static LIST_HEAD(hybrid_tuner_instance_list);
-
-struct tuner_simple_priv {
- unsigned int nr;
- u16 last_div;
-
- struct tuner_i2c_props i2c_props;
- struct list_head hybrid_tuner_instance_list;
-
- unsigned int type;
- struct tunertype *tun;
-
- u32 frequency;
- u32 bandwidth;
-};
-
-/* ---------------------------------------------------------------------- */
-
-static int tuner_read_status(struct dvb_frontend *fe)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- unsigned char byte;
-
- if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
- return 0;
-
- return byte;
-}
-
-static inline int tuner_signal(const int status)
-{
- return (status & TUNER_SIGNAL) << 13;
-}
-
-static inline int tuner_stereo(const int type, const int status)
-{
- switch (type) {
- case TUNER_PHILIPS_FM1216ME_MK3:
- case TUNER_PHILIPS_FM1236_MK3:
- case TUNER_PHILIPS_FM1256_IH3:
- case TUNER_LG_NTSC_TAPE:
- return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
- default:
- return status & TUNER_STEREO;
- }
-}
-
-static inline int tuner_islocked(const int status)
-{
- return (status & TUNER_FL);
-}
-
-static inline int tuner_afcstatus(const int status)
-{
- return (status & TUNER_AFC) - 2;
-}
-
-#if 0 /* unused */
-static inline int tuner_mode(const int status)
-{
- return (status & TUNER_MODE) >> 3;
-}
-#endif
-
-static int simple_get_status(struct dvb_frontend *fe, u32 *status)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- int tuner_status;
-
- if (priv->i2c_props.adap == NULL)
- return -EINVAL;
-
- tuner_status = tuner_read_status(fe);
-
- *status = 0;
-
- if (tuner_islocked(tuner_status))
- *status = TUNER_STATUS_LOCKED;
- if (tuner_stereo(priv->type, tuner_status))
- *status |= TUNER_STATUS_STEREO;
-
- tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
-
- return 0;
-}
-
-static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- int signal;
-
- if (priv->i2c_props.adap == NULL)
- return -EINVAL;
-
- signal = tuner_signal(tuner_read_status(fe));
-
- *strength = signal;
-
- tuner_dbg("Signal strength: %d\n", signal);
-
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static inline char *tuner_param_name(enum param_type type)
-{
- char *name;
-
- switch (type) {
- case TUNER_PARAM_TYPE_RADIO:
- name = "radio";
- break;
- case TUNER_PARAM_TYPE_PAL:
- name = "pal";
- break;
- case TUNER_PARAM_TYPE_SECAM:
- name = "secam";
- break;
- case TUNER_PARAM_TYPE_NTSC:
- name = "ntsc";
- break;
- case TUNER_PARAM_TYPE_DIGITAL:
- name = "digital";
- break;
- default:
- name = "unknown";
- break;
- }
- return name;
-}
-
-static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
- enum param_type desired_type)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- struct tunertype *tun = priv->tun;
- int i;
-
- for (i = 0; i < tun->count; i++)
- if (desired_type == tun->params[i].type)
- break;
-
- /* use default tuner params if desired_type not available */
- if (i == tun->count) {
- tuner_dbg("desired params (%s) undefined for tuner %d\n",
- tuner_param_name(desired_type), priv->type);
- i = 0;
- }
-
- tuner_dbg("using tuner params #%d (%s)\n", i,
- tuner_param_name(tun->params[i].type));
-
- return &tun->params[i];
-}
-
-static int simple_config_lookup(struct dvb_frontend *fe,
- struct tuner_params *t_params,
- int *frequency, u8 *config, u8 *cb)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- int i;
-
- for (i = 0; i < t_params->count; i++) {
- if (*frequency > t_params->ranges[i].limit)
- continue;
- break;
- }
- if (i == t_params->count) {
- tuner_dbg("frequency out of range (%d > %d)\n",
- *frequency, t_params->ranges[i - 1].limit);
- *frequency = t_params->ranges[--i].limit;
- }
- *config = t_params->ranges[i].config;
- *cb = t_params->ranges[i].cb;
-
- tuner_dbg("freq = %d.%02d (%d), range = %d, "
- "config = 0x%02x, cb = 0x%02x\n",
- *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
- i, *config, *cb);
-
- return i;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void simple_set_rf_input(struct dvb_frontend *fe,
- u8 *config, u8 *cb, unsigned int rf)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
-
- switch (priv->type) {
- case TUNER_PHILIPS_TUV1236D:
- switch (rf) {
- case 1:
- *cb |= 0x08;
- break;
- default:
- *cb &= ~0x08;
- break;
- }
- break;
- case TUNER_PHILIPS_FCV1236D:
- switch (rf) {
- case 1:
- *cb |= 0x01;
- break;
- default:
- *cb &= ~0x01;
- break;
- }
- break;
- default:
- break;
- }
-}
-
-static int simple_std_setup(struct dvb_frontend *fe,
- struct analog_parameters *params,
- u8 *config, u8 *cb)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- u8 tuneraddr;
- int rc;
-
- /* tv norm specific stuff for multi-norm tuners */
- switch (priv->type) {
- case TUNER_PHILIPS_SECAM: /* FI1216MF */
- /* 0x01 -> ??? no change ??? */
- /* 0x02 -> PAL BDGHI / SECAM L */
- /* 0x04 -> ??? PAL others / SECAM others ??? */
- *cb &= ~0x03;
- if (params->std & V4L2_STD_SECAM_L)
- /* also valid for V4L2_STD_SECAM */
- *cb |= PHILIPS_MF_SET_STD_L;
- else if (params->std & V4L2_STD_SECAM_LC)
- *cb |= PHILIPS_MF_SET_STD_LC;
- else /* V4L2_STD_B|V4L2_STD_GH */
- *cb |= PHILIPS_MF_SET_STD_BG;
- break;
-
- case TUNER_TEMIC_4046FM5:
- *cb &= ~0x0f;
-
- if (params->std & V4L2_STD_PAL_BG) {
- *cb |= TEMIC_SET_PAL_BG;
-
- } else if (params->std & V4L2_STD_PAL_I) {
- *cb |= TEMIC_SET_PAL_I;
-
- } else if (params->std & V4L2_STD_PAL_DK) {
- *cb |= TEMIC_SET_PAL_DK;
-
- } else if (params->std & V4L2_STD_SECAM_L) {
- *cb |= TEMIC_SET_PAL_L;
-
- }
- break;
-
- case TUNER_PHILIPS_FQ1216ME:
- *cb &= ~0x0f;
-
- if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
- *cb |= PHILIPS_SET_PAL_BGDK;
-
- } else if (params->std & V4L2_STD_PAL_I) {
- *cb |= PHILIPS_SET_PAL_I;
-
- } else if (params->std & V4L2_STD_SECAM_L) {
- *cb |= PHILIPS_SET_PAL_L;
-
- }
- break;
-
- case TUNER_PHILIPS_FCV1236D:
- /* 0x00 -> ATSC antenna input 1 */
- /* 0x01 -> ATSC antenna input 2 */
- /* 0x02 -> NTSC antenna input 1 */
- /* 0x03 -> NTSC antenna input 2 */
- *cb &= ~0x03;
- if (!(params->std & V4L2_STD_ATSC))
- *cb |= 2;
- break;
-
- case TUNER_MICROTUNE_4042FI5:
- /* Set the charge pump for fast tuning */
- *config |= TUNER_CHARGE_PUMP;
- break;
-
- case TUNER_PHILIPS_TUV1236D:
- {
- /* 0x40 -> ATSC antenna input 1 */
- /* 0x48 -> ATSC antenna input 2 */
- /* 0x00 -> NTSC antenna input 1 */
- /* 0x08 -> NTSC antenna input 2 */
- u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};
- *cb &= ~0x40;
- if (params->std & V4L2_STD_ATSC) {
- *cb |= 0x40;
- buffer[1] = 0x04;
- }
- /* set to the correct mode (analog or digital) */
- tuneraddr = priv->i2c_props.addr;
- priv->i2c_props.addr = 0x0a;
- rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2);
- if (2 != rc)
- tuner_warn("i2c i/o error: rc == %d "
- "(should be 2)\n", rc);
- rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2);
- if (2 != rc)
- tuner_warn("i2c i/o error: rc == %d "
- "(should be 2)\n", rc);
- priv->i2c_props.addr = tuneraddr;
- break;
- }
- }
- if (atv_input[priv->nr])
- simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
-
- return 0;
-}
-
-static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
- u16 div, u8 config, u8 cb)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- int rc;
-
- switch (priv->type) {
- case TUNER_LG_TDVS_H06XF:
- /* Set the Auxiliary Byte. */
-#if 0
- buffer[2] &= ~0x20;
- buffer[2] |= 0x18;
- buffer[3] = 0x20;
- tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0], buffer[1], buffer[2], buffer[3]);
-
- rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
- if (4 != rc)
- tuner_warn("i2c i/o error: rc == %d "
- "(should be 4)\n", rc);
-#else
- buffer[0] = buffer[2];
- buffer[0] &= ~0x20;
- buffer[0] |= 0x18;
- buffer[1] = 0x20;
- tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
-
- rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
- if (2 != rc)
- tuner_warn("i2c i/o error: rc == %d "
- "(should be 2)\n", rc);
-#endif
- break;
- case TUNER_MICROTUNE_4042FI5:
- {
- /* FIXME - this may also work for other tuners */
- unsigned long timeout = jiffies + msecs_to_jiffies(1);
- u8 status_byte = 0;
-
- /* Wait until the PLL locks */
- for (;;) {
- if (time_after(jiffies, timeout))
- return 0;
- rc = tuner_i2c_xfer_recv(&priv->i2c_props,
- &status_byte, 1);
- if (1 != rc) {
- tuner_warn("i2c i/o read error: rc == %d "
- "(should be 1)\n", rc);
- break;
- }
- if (status_byte & TUNER_PLL_LOCKED)
- break;
- udelay(10);
- }
-
- /* Set the charge pump for optimized phase noise figure */
- config &= ~TUNER_CHARGE_PUMP;
- buffer[0] = (div>>8) & 0x7f;
- buffer[1] = div & 0xff;
- buffer[2] = config;
- buffer[3] = cb;
- tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0], buffer[1], buffer[2], buffer[3]);
-
- rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
- if (4 != rc)
- tuner_warn("i2c i/o error: rc == %d "
- "(should be 4)\n", rc);
- break;
- }
- }
-
- return 0;
-}
-
-static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
-
- switch (priv->type) {
- case TUNER_TENA_9533_DI:
- case TUNER_YMEC_TVF_5533MF:
- tuner_dbg("This tuner doesn't have FM. "
- "Most cards have a TEA5767 for FM\n");
- return 0;
- case TUNER_PHILIPS_FM1216ME_MK3:
- case TUNER_PHILIPS_FM1236_MK3:
- case TUNER_PHILIPS_FMD1216ME_MK3:
- case TUNER_LG_NTSC_TAPE:
- case TUNER_PHILIPS_FM1256_IH3:
- buffer[3] = 0x19;
- break;
- case TUNER_TNF_5335MF:
- buffer[3] = 0x11;
- break;
- case TUNER_LG_PAL_FM:
- buffer[3] = 0xa5;
- break;
- case TUNER_THOMSON_DTT761X:
- buffer[3] = 0x39;
- break;
- case TUNER_MICROTUNE_4049FM5:
- default:
- buffer[3] = 0xa4;
- break;
- }
-
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int simple_set_tv_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- u8 config, cb;
- u16 div;
- struct tunertype *tun;
- u8 buffer[4];
- int rc, IFPCoff, i;
- enum param_type desired_type;
- struct tuner_params *t_params;
-
- tun = priv->tun;
-
- /* IFPCoff = Video Intermediate Frequency - Vif:
- 940 =16*58.75 NTSC/J (Japan)
- 732 =16*45.75 M/N STD
- 704 =16*44 ATSC (at DVB code)
- 632 =16*39.50 I U.K.
- 622.4=16*38.90 B/G D/K I, L STD
- 592 =16*37.00 D China
- 590 =16.36.875 B Australia
- 543.2=16*33.95 L' STD
- 171.2=16*10.70 FM Radio (at set_radio_freq)
- */
-
- if (params->std == V4L2_STD_NTSC_M_JP) {
- IFPCoff = 940;
- desired_type = TUNER_PARAM_TYPE_NTSC;
- } else if ((params->std & V4L2_STD_MN) &&
- !(params->std & ~V4L2_STD_MN)) {
- IFPCoff = 732;
- desired_type = TUNER_PARAM_TYPE_NTSC;
- } else if (params->std == V4L2_STD_SECAM_LC) {
- IFPCoff = 543;
- desired_type = TUNER_PARAM_TYPE_SECAM;
- } else {
- IFPCoff = 623;
- desired_type = TUNER_PARAM_TYPE_PAL;
- }
-
- t_params = simple_tuner_params(fe, desired_type);
-
- i = simple_config_lookup(fe, t_params, &params->frequency,
- &config, &cb);
-
- div = params->frequency + IFPCoff + offset;
-
- tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, "
- "Offset=%d.%02d MHz, div=%0d\n",
- params->frequency / 16, params->frequency % 16 * 100 / 16,
- IFPCoff / 16, IFPCoff % 16 * 100 / 16,
- offset / 16, offset % 16 * 100 / 16, div);
-
- /* tv norm specific stuff for multi-norm tuners */
- simple_std_setup(fe, params, &config, &cb);
-
- if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
- buffer[0] = config;
- buffer[1] = cb;
- buffer[2] = (div>>8) & 0x7f;
- buffer[3] = div & 0xff;
- } else {
- buffer[0] = (div>>8) & 0x7f;
- buffer[1] = div & 0xff;
- buffer[2] = config;
- buffer[3] = cb;
- }
- priv->last_div = div;
- if (t_params->has_tda9887) {
- struct v4l2_priv_tun_config tda9887_cfg;
- int config = 0;
- int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
- V4L2_STD_SECAM_LC)) &&
- !(params->std & ~(V4L2_STD_SECAM_L |
- V4L2_STD_SECAM_LC));
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &config;
-
- if (params->std == V4L2_STD_SECAM_LC) {
- if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
- config |= TDA9887_PORT1_ACTIVE;
- if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
- config |= TDA9887_PORT2_ACTIVE;
- } else {
- if (t_params->port1_active)
- config |= TDA9887_PORT1_ACTIVE;
- if (t_params->port2_active)
- config |= TDA9887_PORT2_ACTIVE;
- }
- if (t_params->intercarrier_mode)
- config |= TDA9887_INTERCARRIER;
- if (is_secam_l) {
- if (i == 0 && t_params->default_top_secam_low)
- config |= TDA9887_TOP(t_params->default_top_secam_low);
- else if (i == 1 && t_params->default_top_secam_mid)
- config |= TDA9887_TOP(t_params->default_top_secam_mid);
- else if (t_params->default_top_secam_high)
- config |= TDA9887_TOP(t_params->default_top_secam_high);
- } else {
- if (i == 0 && t_params->default_top_low)
- config |= TDA9887_TOP(t_params->default_top_low);
- else if (i == 1 && t_params->default_top_mid)
- config |= TDA9887_TOP(t_params->default_top_mid);
- else if (t_params->default_top_high)
- config |= TDA9887_TOP(t_params->default_top_high);
- }
- if (t_params->default_pll_gating_18)
- config |= TDA9887_GATING_18;
- i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
- &tda9887_cfg);
- }
- tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0], buffer[1], buffer[2], buffer[3]);
-
- rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
- if (4 != rc)
- tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
-
- simple_post_tune(fe, &buffer[0], div, config, cb);
-
- return 0;
-}
-
-static int simple_set_radio_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tunertype *tun;
- struct tuner_simple_priv *priv = fe->tuner_priv;
- u8 buffer[4];
- u16 div;
- int rc, j;
- struct tuner_params *t_params;
- unsigned int freq = params->frequency;
-
- tun = priv->tun;
-
- for (j = tun->count-1; j > 0; j--)
- if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
- break;
- /* default t_params (j=0) will be used if desired type wasn't found */
- t_params = &tun->params[j];
-
- /* Select Radio 1st IF used */
- switch (t_params->radio_if) {
- case 0: /* 10.7 MHz */
- freq += (unsigned int)(10.7*16000);
- break;
- case 1: /* 33.3 MHz */
- freq += (unsigned int)(33.3*16000);
- break;
- case 2: /* 41.3 MHz */
- freq += (unsigned int)(41.3*16000);
- break;
- default:
- tuner_warn("Unsupported radio_if value %d\n",
- t_params->radio_if);
- return 0;
- }
-
- /* Bandswitch byte */
- simple_radio_bandswitch(fe, &buffer[0]);
-
- buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
- TUNER_RATIO_SELECT_50; /* 50 kHz step */
-
- /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
- freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
- freq * (1/800) */
- div = (freq + 400) / 800;
-
- if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
- buffer[0] = buffer[2];
- buffer[1] = buffer[3];
- buffer[2] = (div>>8) & 0x7f;
- buffer[3] = div & 0xff;
- } else {
- buffer[0] = (div>>8) & 0x7f;
- buffer[1] = div & 0xff;
- }
-
- tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0], buffer[1], buffer[2], buffer[3]);
- priv->last_div = div;
-
- if (t_params->has_tda9887) {
- int config = 0;
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &config;
-
- if (t_params->port1_active &&
- !t_params->port1_fm_high_sensitivity)
- config |= TDA9887_PORT1_ACTIVE;
- if (t_params->port2_active &&
- !t_params->port2_fm_high_sensitivity)
- config |= TDA9887_PORT2_ACTIVE;
- if (t_params->intercarrier_mode)
- config |= TDA9887_INTERCARRIER;
-/* if (t_params->port1_set_for_fm_mono)
- config &= ~TDA9887_PORT1_ACTIVE;*/
- if (t_params->fm_gain_normal)
- config |= TDA9887_GAIN_NORMAL;
- if (t_params->radio_if == 2)
- config |= TDA9887_RIF_41_3;
- i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
- &tda9887_cfg);
- }
- rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
- if (4 != rc)
- tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
-
- return 0;
-}
-
-static int simple_set_params(struct dvb_frontend *fe,
- struct analog_parameters *params)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- int ret = -EINVAL;
-
- if (priv->i2c_props.adap == NULL)
- return -EINVAL;
-
- switch (params->mode) {
- case V4L2_TUNER_RADIO:
- ret = simple_set_radio_freq(fe, params);
- priv->frequency = params->frequency * 125 / 2;
- break;
- case V4L2_TUNER_ANALOG_TV:
- case V4L2_TUNER_DIGITAL_TV:
- ret = simple_set_tv_freq(fe, params);
- priv->frequency = params->frequency * 62500;
- break;
- }
- priv->bandwidth = 0;
-
- return ret;
-}
-
-static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
-
- switch (priv->type) {
- case TUNER_PHILIPS_FMD1216ME_MK3:
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
- params->frequency >= 158870000)
- buf[3] |= 0x08;
- break;
- case TUNER_PHILIPS_TD1316:
- /* determine band */
- buf[3] |= (params->frequency < 161000000) ? 1 :
- (params->frequency < 444000000) ? 2 : 4;
-
- /* setup PLL filter */
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
- buf[3] |= 1 << 3;
- break;
- case TUNER_PHILIPS_TUV1236D:
- case TUNER_PHILIPS_FCV1236D:
- {
- unsigned int new_rf;
-
- if (dtv_input[priv->nr])
- new_rf = dtv_input[priv->nr];
- else
- switch (params->u.vsb.modulation) {
- case QAM_64:
- case QAM_256:
- new_rf = 1;
- break;
- case VSB_8:
- default:
- new_rf = 0;
- break;
- }
- simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
- break;
- }
- default:
- break;
- }
-}
-
-static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
-{
- /* This function returns the tuned frequency on success, 0 on error */
- struct tuner_simple_priv *priv = fe->tuner_priv;
- struct tunertype *tun = priv->tun;
- static struct tuner_params *t_params;
- u8 config, cb;
- u32 div;
- int ret, frequency = params->frequency / 62500;
-
- t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
- ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
- if (ret < 0)
- return 0; /* failure */
-
- div = ((frequency + t_params->iffreq) * 62500 + offset +
- tun->stepsize/2) / tun->stepsize;
-
- buf[0] = div >> 8;
- buf[1] = div & 0xff;
- buf[2] = config;
- buf[3] = cb;
-
- simple_set_dvb(fe, buf, params);
-
- tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
- tun->name, div, buf[0], buf[1], buf[2], buf[3]);
-
- /* calculate the frequency we set it to */
- return (div * tun->stepsize) - t_params->iffreq;
-}
-
-static int simple_dvb_calc_regs(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
- u8 *buf, int buf_len)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- u32 frequency;
-
- if (buf_len < 5)
- return -EINVAL;
-
- frequency = simple_dvb_configure(fe, buf+1, params);
- if (frequency == 0)
- return -EINVAL;
-
- buf[0] = priv->i2c_props.addr;
-
- priv->frequency = frequency;
- priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
- params->u.ofdm.bandwidth : 0;
-
- return 5;
-}
-
-static int simple_dvb_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- u32 prev_freq, prev_bw;
- int ret;
- u8 buf[5];
-
- if (priv->i2c_props.adap == NULL)
- return -EINVAL;
-
- prev_freq = priv->frequency;
- prev_bw = priv->bandwidth;
-
- ret = simple_dvb_calc_regs(fe, params, buf, 5);
- if (ret != 5)
- goto fail;
-
- /* put analog demod in standby when tuning digital */
- if (fe->ops.analog_ops.standby)
- fe->ops.analog_ops.standby(fe);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- /* buf[0] contains the i2c address, but *
- * we already have it in i2c_props.addr */
- ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
- if (ret != 4)
- goto fail;
-
- return 0;
-fail:
- /* calc_regs sets frequency and bandwidth. if we failed, unset them */
- priv->frequency = prev_freq;
- priv->bandwidth = prev_bw;
-
- return ret;
-}
-
-static int simple_init(struct dvb_frontend *fe)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
-
- if (priv->i2c_props.adap == NULL)
- return -EINVAL;
-
- if (priv->tun->initdata) {
- int ret;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- ret = tuner_i2c_xfer_send(&priv->i2c_props,
- priv->tun->initdata + 1,
- priv->tun->initdata[0]);
- if (ret != priv->tun->initdata[0])
- return ret;
- }
-
- return 0;
-}
-
-static int simple_sleep(struct dvb_frontend *fe)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
-
- if (priv->i2c_props.adap == NULL)
- return -EINVAL;
-
- if (priv->tun->sleepdata) {
- int ret;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- ret = tuner_i2c_xfer_send(&priv->i2c_props,
- priv->tun->sleepdata + 1,
- priv->tun->sleepdata[0]);
- if (ret != priv->tun->sleepdata[0])
- return ret;
- }
-
- return 0;
-}
-
-static int simple_release(struct dvb_frontend *fe)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
-
- mutex_lock(&tuner_simple_list_mutex);
-
- if (priv)
- hybrid_tuner_release_state(priv);
-
- mutex_unlock(&tuner_simple_list_mutex);
-
- fe->tuner_priv = NULL;
-
- return 0;
-}
-
-static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- *frequency = priv->frequency;
- return 0;
-}
-
-static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
-{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- *bandwidth = priv->bandwidth;
- return 0;
-}
-
-static struct dvb_tuner_ops simple_tuner_ops = {
-#if 0
- .info = {
- .name = "tuner-simple",
- .frequency_min = ,
- .frequency_max = ,
- .frequency_step = ,
- },
-#endif
- .init = simple_init,
- .sleep = simple_sleep,
- .set_analog_params = simple_set_params,
- .set_params = simple_dvb_set_params,
- .calc_regs = simple_dvb_calc_regs,
- .release = simple_release,
- .get_frequency = simple_get_frequency,
- .get_bandwidth = simple_get_bandwidth,
- .get_status = simple_get_status,
- .get_rf_strength = simple_get_rf_strength,
-};
-
-struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr,
- unsigned int type)
-{
- struct tuner_simple_priv *priv = NULL;
- int instance;
-
- if (type >= tuner_count) {
- printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
- __FUNCTION__, type, tuner_count-1);
- return NULL;
- }
-
- /* If i2c_adap is set, check that the tuner is at the correct address.
- * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
- * by the digital demod via calc_regs.
- */
- if (i2c_adap != NULL) {
- u8 b[1];
- struct i2c_msg msg = {
- .addr = i2c_addr, .flags = I2C_M_RD,
- .buf = b, .len = 1,
- };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- if (1 != i2c_transfer(i2c_adap, &msg, 1))
- tuner_warn("unable to probe %s, proceeding anyway.",
- tuners[type].name);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
-
- mutex_lock(&tuner_simple_list_mutex);
-
- instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
- hybrid_tuner_instance_list,
- i2c_adap, i2c_addr,
- "tuner-simple");
- switch (instance) {
- case 0:
- mutex_unlock(&tuner_simple_list_mutex);
- return NULL;
- break;
- case 1:
- fe->tuner_priv = priv;
-
- priv->type = type;
- priv->tun = &tuners[type];
- priv->nr = simple_devcount++;
- break;
- default:
- fe->tuner_priv = priv;
-#if 0
- /* caller didn't pass in a configuration last time
- * use current configuration, instead */
- if (!priv->tun) {
- priv->type = type;
- priv->tun = &tuners[type];
- }
-#endif
- break;
- }
-
- mutex_unlock(&tuner_simple_list_mutex);
-
- memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
- sizeof(struct dvb_tuner_ops));
-
- tuner_info("type set to %d (%s)\n", type, priv->tun->name);
-
- if ((debug) || ((atv_input[priv->nr] > 0) ||
- (dtv_input[priv->nr] > 0))) {
- if (0 == atv_input[priv->nr])
- tuner_info("tuner %d atv rf input will be "
- "autoselected\n", priv->nr);
- else
- tuner_info("tuner %d atv rf input will be "
- "set to input %d (insmod option)\n",
- priv->nr, atv_input[priv->nr]);
- if (0 == dtv_input[priv->nr])
- tuner_info("tuner %d dtv rf input will be "
- "autoselected\n", priv->nr);
- else
- tuner_info("tuner %d dtv rf input will be "
- "set to input %d (insmod option)\n",
- priv->nr, dtv_input[priv->nr]);
- }
-
- strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,
- sizeof(fe->ops.tuner_ops.info.name));
-
- return fe;
-}
-EXPORT_SYMBOL_GPL(simple_tuner_attach);
-
-MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
-MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
-MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/linux/drivers/media/video/tuner-simple.h b/linux/drivers/media/video/tuner-simple.h
deleted file mode 100644
index bf425f325..000000000
--- a/linux/drivers/media/video/tuner-simple.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TUNER_SIMPLE_H__
-#define __TUNER_SIMPLE_H__
-
-#include <linux/i2c.h>
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE))
-extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr,
- unsigned int type);
-#else
-static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c_adap,
- u8 i2c_addr,
- unsigned int type)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
- return NULL;
-}
-#endif
-
-#endif /* __TUNER_SIMPLE_H__ */
diff --git a/linux/drivers/media/video/tuner-types.c b/linux/drivers/media/video/tuner-types.c
deleted file mode 100644
index b3f0f62e0..000000000
--- a/linux/drivers/media/video/tuner-types.c
+++ /dev/null
@@ -1,1653 +0,0 @@
-/*
- *
- * i2c tv tuner chip device type database.
- *
- */
-
-#include <linux/i2c.h>
-#include <media/tuner.h>
-#include <media/tuner-types.h>
-#include "compat.h"
-
-/* ---------------------------------------------------------------------- */
-
-/*
- * The floats in the tuner struct are computed at compile time
- * by gcc and cast back to integers. Thus we don't violate the
- * "no float in kernel" rule.
- *
- * A tuner_range may be referenced by multiple tuner_params structs.
- * There are many duplicates in here. Reusing tuner_range structs,
- * rather than defining new ones for each tuner, will cut down on
- * memory usage, and is preferred when possible.
- *
- * Each tuner_params array may contain one or more elements, one
- * for each video standard.
- *
- * FIXME: tuner_params struct contains an element, tda988x. We must
- * set this for all tuners that contain a tda988x chip, and then we
- * can remove this setting from the various card structs.
- *
- * FIXME: Right now, all tuners are using the first tuner_params[]
- * array element for analog mode. In the future, we will be merging
- * similar tuner definitions together, such that each tuner definition
- * will have a tuner_params struct for each available video standard.
- * At that point, the tuner_params[] array element will be chosen
- * based on the video standard in use.
- */
-
-/* The following was taken from dvb-pll.c: */
-
-/* Set AGC TOP value to 103 dBuV:
- * 0x80 = Control Byte
- * 0x40 = 250 uA charge pump (irrelevant)
- * 0x18 = Aux Byte to follow
- * 0x06 = 64.5 kHz divider (irrelevant)
- * 0x01 = Disable Vt (aka sleep)
- *
- * 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
- * 0x50 = AGC Take over point = 103 dBuV
- */
-static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
-
-/* 0x04 = 166.67 kHz divider
- *
- * 0x80 = AGC Time constant 50ms Iagc = 9 uA
- * 0x20 = AGC Take over point = 112 dBuV
- */
-static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
-
-/* 0-9 */
-/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */
-
-static struct tuner_range tuner_temic_pal_ranges[] = {
- { 16 * 140.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
- { 16 * 999.99 , 0x8e, 0x01, },
-};
-
-static struct tuner_params tuner_temic_pal_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_pal_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */
-
-static struct tuner_range tuner_philips_pal_i_ranges[] = {
- { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_pal_i_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_philips_pal_i_ranges,
- .count = ARRAY_SIZE(tuner_philips_pal_i_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */
-
-static struct tuner_range tuner_philips_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_ntsc_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_philips_ntsc_ranges),
- .cb_first_if_lower_freq = 1,
- },
-};
-
-/* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */
-
-static struct tuner_range tuner_philips_secam_ranges[] = {
- { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, },
- { 16 * 447.25 /*MHz*/, 0x8e, 0x97, },
- { 16 * 999.99 , 0x8e, 0x37, },
-};
-
-static struct tuner_params tuner_philips_secam_params[] = {
- {
- .type = TUNER_PARAM_TYPE_SECAM,
- .ranges = tuner_philips_secam_ranges,
- .count = ARRAY_SIZE(tuner_philips_secam_ranges),
- .cb_first_if_lower_freq = 1,
- },
-};
-
-/* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_pal_ranges[] = {
- { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 447.25 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_pal_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_philips_pal_ranges,
- .count = ARRAY_SIZE(tuner_philips_pal_ranges),
- .cb_first_if_lower_freq = 1,
- },
-};
-
-/* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */
-
-static struct tuner_range tuner_temic_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 463.25 /*MHz*/, 0x8e, 0x04, },
- { 16 * 999.99 , 0x8e, 0x01, },
-};
-
-static struct tuner_params tuner_temic_ntsc_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_temic_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_temic_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */
-
-static struct tuner_range tuner_temic_pal_i_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0x8e, 0x02, },
- { 16 * 450.00 /*MHz*/, 0x8e, 0x04, },
- { 16 * 999.99 , 0x8e, 0x01, },
-};
-
-static struct tuner_params tuner_temic_pal_i_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_pal_i_ranges,
- .count = ARRAY_SIZE(tuner_temic_pal_i_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */
-
-static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_temic_4036fy5_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */
-
-static struct tuner_range tuner_alps_tsb_1_ranges[] = {
- { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 385.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_alps_tsb_1_ranges,
- .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
- },
-};
-
-/* 10-19 */
-/* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_alps_tsb_1_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_alps_tsb_1_ranges,
- .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges),
- },
-};
-
-/* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */
-
-static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = {
- { 16 * 133.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 351.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_alps_tsbb5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_alps_tsb_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
- },
-};
-
-/* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */
-
-static struct tuner_params tuner_alps_tsbe5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_alps_tsb_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
- },
-};
-
-/* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */
-
-static struct tuner_params tuner_alps_tsbc5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_alps_tsb_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */
-
-static struct tuner_range tuner_lg_pal_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 450.00 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4006fh5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_pal_ranges,
- .count = ARRAY_SIZE(tuner_lg_pal_ranges),
- },
-};
-
-/* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */
-
-static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = {
- { 16 * 137.25 /*MHz*/, 0x8e, 0x14, },
- { 16 * 385.25 /*MHz*/, 0x8e, 0x12, },
- { 16 * 999.99 , 0x8e, 0x11, },
-};
-
-static struct tuner_params tuner_alps_tshc6_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_alps_tshc6_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */
-
-static struct tuner_range tuner_temic_pal_dk_ranges[] = {
- { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 456.25 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_pal_dk_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_pal_dk_ranges,
- .count = ARRAY_SIZE(tuner_temic_pal_dk_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */
-
-static struct tuner_range tuner_philips_ntsc_m_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_ntsc_m_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_ntsc_m_ranges,
- .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */
-
-static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = {
- { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_40x6f_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4006fn5_multi_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_40x6f_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
- },
-};
-
-/* 20-29 */
-/* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */
-
-static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = {
- { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 464.00 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4009f_5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_4009f_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */
-
-static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = {
- { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_temic_4039fr5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4046fm5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_40x6f_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */
-
-static struct tuner_params tuner_philips_pal_dk_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_pal_ranges,
- .count = ARRAY_SIZE(tuner_lg_pal_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */
-
-static struct tuner_params tuner_philips_fq1216me_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_pal_ranges,
- .count = ARRAY_SIZE(tuner_lg_pal_ranges),
- .has_tda9887 = 1,
- .port1_active = 1,
- .port2_active = 1,
- .port2_invert_for_secam_lc = 1,
- },
-};
-
-/* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */
-
-static struct tuner_params tuner_lg_pal_i_fm_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_pal_ranges,
- .count = ARRAY_SIZE(tuner_lg_pal_ranges),
- },
-};
-
-/* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */
-
-static struct tuner_params tuner_lg_pal_i_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_pal_ranges,
- .count = ARRAY_SIZE(tuner_lg_pal_ranges),
- },
-};
-
-/* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */
-
-static struct tuner_range tuner_lg_ntsc_fm_ranges[] = {
- { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 497.00 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_lg_ntsc_fm_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_lg_ntsc_fm_ranges,
- .count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges),
- },
-};
-
-/* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */
-
-static struct tuner_params tuner_lg_pal_fm_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_pal_ranges,
- .count = ARRAY_SIZE(tuner_lg_pal_ranges),
- },
-};
-
-/* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */
-
-static struct tuner_params tuner_lg_pal_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_pal_ranges,
- .count = ARRAY_SIZE(tuner_lg_pal_ranges),
- },
-};
-
-/* 30-39 */
-/* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_4009f_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
- },
-};
-
-/* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */
-
-static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = {
- { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 317.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_sharp_2u5jf5540_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_sharp_2u5jf5540_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */
-
-static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = {
- { 16 * 169 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 464 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_samsung_pal_tcpm9091pd27_ranges,
- .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4106fh5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_4009f_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */
-
-static struct tuner_params tuner_temic_4012fy5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_pal_ranges),
- },
-};
-
-/* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */
-
-static struct tuner_params tuner_temic_4136_fy5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_temic_4x3x_f_5_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */
-
-static struct tuner_range tuner_lg_new_tapc_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0x8e, 0x01, },
- { 16 * 450.00 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_lg_pal_new_tapc_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_new_tapc_ranges,
- .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */
-
-static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = {
- { 16 * 158.00 /*MHz*/, 0x8e, 0x01, },
- { 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_fm1216me_mk3_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_fm1216me_mk3_pal_ranges,
- .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
- .cb_first_if_lower_freq = 1,
- .has_tda9887 = 1,
- .port1_active = 1,
- .port2_active = 1,
- .port2_invert_for_secam_lc = 1,
- .port1_fm_high_sensitivity = 1,
- .default_top_mid = -2,
- .default_top_secam_mid = -2,
- .default_top_secam_high = -2,
- },
-};
-
-/* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */
-
-static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_lg_new_tapc_ranges,
- .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
- },
-};
-
-/* 40-49 */
-/* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */
-
-static struct tuner_params tuner_hitachi_ntsc_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_lg_new_tapc_ranges,
- .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = {
- { 16 * 140.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, },
- { 16 * 999.99 , 0x8e, 0xcf, },
-};
-
-static struct tuner_params tuner_philips_pal_mk_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_philips_pal_mk_pal_ranges,
- .count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges),
- },
-};
-
-/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */
-
-static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x8e, 0xa2, },
- { 16 * 451.25 /*MHz*/, 0x8e, 0x92, },
- { 16 * 999.99 , 0x8e, 0x32, },
-};
-
-static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = {
- { 16 * 159.00 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_philips_fcv1236d_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_fcv1236d_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges),
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_philips_fcv1236d_atsc_ranges,
- .count = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges),
- .iffreq = 16 * 44.00,
- },
-};
-
-/* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */
-
-static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
- { 16 * 442.00 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_fm1236_mk3_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_fm1236_mk3_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
- .cb_first_if_lower_freq = 1,
- .has_tda9887 = 1,
- .port1_active = 1,
- .port2_active = 1,
- .port1_fm_high_sensitivity = 1,
- },
-};
-
-/* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */
-
-static struct tuner_params tuner_philips_4in1_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_fm1236_mk3_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */
-
-static struct tuner_params tuner_microtune_4049_fm5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_temic_4009f_5_pal_ranges,
- .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
- .has_tda9887 = 1,
- .port1_invert_for_secam_lc = 1,
- .default_pll_gating_18 = 1,
- .fm_gain_normal=1,
- .radio_if = 1, /* 33.3 MHz */
- },
-};
-
-/* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */
-
-static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0xce, 0x01, },
- { 16 * 454.00 /*MHz*/, 0xce, 0x02, },
- { 16 * 999.99 , 0xce, 0x08, },
-};
-
-static struct tuner_params tuner_panasonic_vp27_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_panasonic_vp27_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
- .has_tda9887 = 1,
- .intercarrier_mode = 1,
- .default_top_low = -3,
- .default_top_mid = -3,
- .default_top_high = -3,
- },
-};
-
-/* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */
-
-static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = {
- { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 463.25 /*MHz*/, 0x8e, 0x90, },
- { 16 * 999.99 , 0x8e, 0x30, },
-};
-
-static struct tuner_params tuner_tnf_8831bgff_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_tnf_8831bgff_pal_ranges,
- .count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges),
- },
-};
-
-/* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */
-
-static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = {
- { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, },
- { 16 * 457.00 /*MHz*/, 0x8e, 0x94, },
- { 16 * 999.99 , 0x8e, 0x31, },
-};
-
-static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = {
- { 16 * 162.00 /*MHz*/, 0x8e, 0xa1, },
- { 16 * 457.00 /*MHz*/, 0x8e, 0x91, },
- { 16 * 999.99 , 0x8e, 0x31, },
-};
-
-static struct tuner_params tuner_microtune_4042fi5_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_microtune_4042fi5_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges),
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_microtune_4042fi5_atsc_ranges,
- .count = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges),
- .iffreq = 16 * 44.00 /*MHz*/,
- },
-};
-
-/* 50-59 */
-/* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */
-
-static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = {
- { 16 * 172.00 /*MHz*/, 0x8e, 0x01, },
- { 16 * 448.00 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_tcl_2002n_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_tcl_2002n_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges),
- .cb_first_if_lower_freq = 1,
- },
-};
-
-/* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */
-
-static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_fm1236_mk3_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
- .radio_if = 1, /* 33.3 MHz */
- },
-};
-
-/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */
-
-/* single range used for both ntsc and atsc */
-static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x8e, 0x39, },
- { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, },
- { 16 * 999.99 , 0x8e, 0x3c, },
-};
-
-static struct tuner_params tuner_thomson_dtt7610_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_thomson_dtt7610_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_thomson_dtt7610_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
- .iffreq = 16 * 44.00 /*MHz*/,
- },
-};
-
-/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */
-
-static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x8e, 0x41, },
- { 16 * 454.00 /*MHz*/, 0x8e, 0x42, },
- { 16 * 999.99 , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_philips_fq1286_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_fq1286_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */
-
-static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = {
- { 16 * 170.00 /*MHz*/, 0xce, 0x01, },
- { 16 * 450.00 /*MHz*/, 0xce, 0x02, },
- { 16 * 999.99 , 0xce, 0x08, },
-};
-
-static struct tuner_params tuner_tcl_2002mb_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_tcl_2002mb_pal_ranges,
- .count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0xce, 0x01, },
- { 16 * 442.00 /*MHz*/, 0xce, 0x02, },
- { 16 * 999.99 , 0xce, 0x04, },
-};
-
-static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_philips_fq12_6a___mk4_pal_ranges,
- .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges),
- .has_tda9887 = 1,
- .port1_active = 1,
- .port2_invert_for_secam_lc = 1,
- .default_top_mid = -2,
- .default_top_secam_low = -2,
- .default_top_secam_mid = -2,
- .default_top_secam_high = -2,
- },
-};
-
-/* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */
-
-static struct tuner_params tuner_philips_fq1236a_mk4_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_fm1236_mk3_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */
-
-static struct tuner_params tuner_ymec_tvf_8531mf_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_ntsc_m_ranges,
- .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges),
- },
-};
-
-/* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */
-
-static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x8e, 0x01, },
- { 16 * 454.00 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_ymec_tvf_5533mf_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges),
- },
-};
-
-/* 60-69 */
-/* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */
-/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
-
-static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = {
- { 16 * 145.25 /*MHz*/, 0x8e, 0x39, },
- { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, },
- { 16 * 999.99 , 0x8e, 0x3c, },
-};
-
-static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = {
- { 16 * 147.00 /*MHz*/, 0x8e, 0x39, },
- { 16 * 417.00 /*MHz*/, 0x8e, 0x3a, },
- { 16 * 999.99 , 0x8e, 0x3c, },
-};
-
-static struct tuner_params tuner_thomson_dtt761x_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_thomson_dtt761x_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
- .has_tda9887 = 1,
- .fm_gain_normal = 1,
- .radio_if = 2, /* 41.3 MHz */
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_thomson_dtt761x_atsc_ranges,
- .count = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges),
- .iffreq = 16 * 44.00, /*MHz*/
- },
-};
-
-/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */
-
-static struct tuner_range tuner_tena_9533_di_pal_ranges[] = {
- { 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x04, },
-};
-
-static struct tuner_params tuner_tena_9533_di_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_tena_9533_di_pal_ranges,
- .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0x86, 0x51, },
- { 16 * 442.00 /*MHz*/, 0x86, 0x52, },
- { 16 * 999.99 , 0x86, 0x54, },
-};
-
-static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = {
- { 16 * 143.87 /*MHz*/, 0xbc, 0x41 },
- { 16 * 158.87 /*MHz*/, 0xf4, 0x41 },
- { 16 * 329.87 /*MHz*/, 0xbc, 0x42 },
- { 16 * 441.87 /*MHz*/, 0xf4, 0x42 },
- { 16 * 625.87 /*MHz*/, 0xbc, 0x44 },
- { 16 * 803.87 /*MHz*/, 0xf4, 0x44 },
- { 16 * 999.99 , 0xfc, 0x44 },
-};
-
-static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
- .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
- .has_tda9887 = 1,
- .port1_active = 1,
- .port2_active = 1,
- .port2_fm_high_sensitivity = 1,
- .port2_invert_for_secam_lc = 1,
- .port1_set_for_fm_mono = 1,
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
- .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
- .iffreq = 16 * 36.125, /*MHz*/
- },
-};
-
-
-/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
-
-static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
- { 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
- { 16 * 450.00 /*MHz*/, 0x8e, 0x02 },
- { 16 * 999.99 , 0x8e, 0x04 },
-};
-
-static struct tuner_range tuner_tua6034_atsc_ranges[] = {
- { 16 * 165.00 /*MHz*/, 0xce, 0x01 },
- { 16 * 450.00 /*MHz*/, 0xce, 0x02 },
- { 16 * 999.99 , 0xce, 0x04 },
-};
-
-static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_tua6034_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges),
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_tua6034_atsc_ranges,
- .count = ARRAY_SIZE(tuner_tua6034_atsc_ranges),
- .iffreq = 16 * 44.00,
- },
-};
-
-/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
-
-static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = {
- { 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges,
- .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges),
- },
-};
-
-/* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */
-
-static struct tuner_range tuner_lg_taln_ntsc_ranges[] = {
- { 16 * 137.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 373.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = {
- { 16 * 150.00 /*MHz*/, 0x8e, 0x01, },
- { 16 * 425.00 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_lg_taln_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_lg_taln_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges),
- },{
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_lg_taln_pal_secam_ranges,
- .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges),
- },
-};
-
-/* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */
-
-static struct tuner_range tuner_philips_td1316_pal_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, },
- { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, },
- { 16 * 999.99 , 0xc8, 0xa4, },
-};
-
-static struct tuner_range tuner_philips_td1316_dvb_ranges[] = {
- { 16 * 93.834 /*MHz*/, 0xca, 0x60, },
- { 16 * 123.834 /*MHz*/, 0xca, 0xa0, },
- { 16 * 163.834 /*MHz*/, 0xca, 0xc0, },
- { 16 * 253.834 /*MHz*/, 0xca, 0x60, },
- { 16 * 383.834 /*MHz*/, 0xca, 0xa0, },
- { 16 * 443.834 /*MHz*/, 0xca, 0xc0, },
- { 16 * 583.834 /*MHz*/, 0xca, 0x60, },
- { 16 * 793.834 /*MHz*/, 0xca, 0xa0, },
- { 16 * 999.999 , 0xca, 0xe0, },
-};
-
-static struct tuner_params tuner_philips_td1316_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_philips_td1316_pal_ranges,
- .count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges),
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_philips_td1316_dvb_ranges,
- .count = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges),
- .iffreq = 16 * 36.166667 /*MHz*/,
- },
-};
-
-/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */
-
-static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0xce, 0x01, },
- { 16 * 454.00 /*MHz*/, 0xce, 0x02, },
- { 16 * 999.99 , 0xce, 0x04, },
-};
-
-static struct tuner_range tuner_tuv1236d_atsc_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0xc6, 0x41, },
- { 16 * 454.00 /*MHz*/, 0xc6, 0x42, },
- { 16 * 999.99 , 0xc6, 0x44, },
-};
-
-static struct tuner_params tuner_tuv1236d_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_tuv1236d_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges),
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_tuv1236d_atsc_ranges,
- .count = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges),
- .iffreq = 16 * 44.00,
- },
-};
-
-/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */
-/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF
- * but it is expected to work also with other Tenna/Ymec
- * models based on TI SN 761677 chip on both PAL and NTSC
- */
-
-static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = {
- { 16 * 168.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 471.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = {
- { 16 * 169.25 /*MHz*/, 0x8e, 0x01, },
- { 16 * 469.25 /*MHz*/, 0x8e, 0x02, },
- { 16 * 999.99 , 0x8e, 0x08, },
-};
-
-static struct tuner_params tuner_tnf_5335mf_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_tnf_5335mf_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges),
- },
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_tnf_5335_d_if_pal_ranges,
- .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges),
- },
-};
-
-/* 70-79 */
-/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */
-
-/* '+ 4' turns on the Low Noise Amplifier */
-static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = {
- { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, },
- { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, },
- { 16 * 999.99 , 0xce, 0x08 + 4, },
-};
-
-static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
- {
- .type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
- .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
- },
-};
-
-/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */
-
-static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = {
- { 16 * 160.00 /*MHz*/, 0xfe, 0x11, },
- { 16 * 442.00 /*MHz*/, 0xf6, 0x12, },
- { 16 * 999.99 , 0xf6, 0x18, },
-};
-
-static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = {
- { 16 * 250.00 /*MHz*/, 0xb4, 0x12, },
- { 16 * 455.00 /*MHz*/, 0xfe, 0x11, },
- { 16 * 775.50 /*MHz*/, 0xbc, 0x18, },
- { 16 * 999.99 , 0xf4, 0x18, },
-};
-
-static struct tuner_params tuner_thomson_fe6600_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_thomson_fe6600_pal_ranges,
- .count = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges),
- },
- {
- .type = TUNER_PARAM_TYPE_DIGITAL,
- .ranges = tuner_thomson_fe6600_dvb_ranges,
- .count = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges),
- .iffreq = 16 * 36.125 /*MHz*/,
- },
-};
-
-/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */
-
-/* '+ 4' turns on the Low Noise Amplifier */
-static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = {
- { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, },
- { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, },
- { 16 * 999.99 , 0xce, 0x08 + 4, },
-};
-
-static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
- {
- .type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges,
- .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges),
- .has_tda9887 = 1,
- .port1_active = 1,
- .port2_active = 1,
- .port2_invert_for_secam_lc = 1,
- },
-};
-
-/* --------------------------------------------------------------------- */
-
-struct tunertype tuners[] = {
- /* 0-9 */
- [TUNER_TEMIC_PAL] = { /* TEMIC PAL */
- .name = "Temic PAL (4002 FH5)",
- .params = tuner_temic_pal_params,
- .count = ARRAY_SIZE(tuner_temic_pal_params),
- },
- [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */
- .name = "Philips PAL_I (FI1246 and compatibles)",
- .params = tuner_philips_pal_i_params,
- .count = ARRAY_SIZE(tuner_philips_pal_i_params),
- },
- [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */
- .name = "Philips NTSC (FI1236,FM1236 and compatibles)",
- .params = tuner_philips_ntsc_params,
- .count = ARRAY_SIZE(tuner_philips_ntsc_params),
- },
- [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */
- .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)",
- .params = tuner_philips_secam_params,
- .count = ARRAY_SIZE(tuner_philips_secam_params),
- },
- [TUNER_ABSENT] = { /* Tuner Absent */
- .name = "NoTuner",
- },
- [TUNER_PHILIPS_PAL] = { /* Philips PAL */
- .name = "Philips PAL_BG (FI1216 and compatibles)",
- .params = tuner_philips_pal_params,
- .count = ARRAY_SIZE(tuner_philips_pal_params),
- },
- [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */
- .name = "Temic NTSC (4032 FY5)",
- .params = tuner_temic_ntsc_params,
- .count = ARRAY_SIZE(tuner_temic_ntsc_params),
- },
- [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */
- .name = "Temic PAL_I (4062 FY5)",
- .params = tuner_temic_pal_i_params,
- .count = ARRAY_SIZE(tuner_temic_pal_i_params),
- },
- [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */
- .name = "Temic NTSC (4036 FY5)",
- .params = tuner_temic_4036fy5_ntsc_params,
- .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params),
- },
- [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */
- .name = "Alps HSBH1",
- .params = tuner_alps_tsbh1_ntsc_params,
- .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params),
- },
-
- /* 10-19 */
- [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */
- .name = "Alps TSBE1",
- .params = tuner_alps_tsb_1_params,
- .count = ARRAY_SIZE(tuner_alps_tsb_1_params),
- },
- [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */
- .name = "Alps TSBB5",
- .params = tuner_alps_tsbb5_params,
- .count = ARRAY_SIZE(tuner_alps_tsbb5_params),
- },
- [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */
- .name = "Alps TSBE5",
- .params = tuner_alps_tsbe5_params,
- .count = ARRAY_SIZE(tuner_alps_tsbe5_params),
- },
- [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */
- .name = "Alps TSBC5",
- .params = tuner_alps_tsbc5_params,
- .count = ARRAY_SIZE(tuner_alps_tsbc5_params),
- },
- [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */
- .name = "Temic PAL_BG (4006FH5)",
- .params = tuner_temic_4006fh5_params,
- .count = ARRAY_SIZE(tuner_temic_4006fh5_params),
- },
- [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */
- .name = "Alps TSCH6",
- .params = tuner_alps_tshc6_params,
- .count = ARRAY_SIZE(tuner_alps_tshc6_params),
- },
- [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */
- .name = "Temic PAL_DK (4016 FY5)",
- .params = tuner_temic_pal_dk_params,
- .count = ARRAY_SIZE(tuner_temic_pal_dk_params),
- },
- [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */
- .name = "Philips NTSC_M (MK2)",
- .params = tuner_philips_ntsc_m_params,
- .count = ARRAY_SIZE(tuner_philips_ntsc_m_params),
- },
- [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */
- .name = "Temic PAL_I (4066 FY5)",
- .params = tuner_temic_4066fy5_pal_i_params,
- .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params),
- },
- [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */
- .name = "Temic PAL* auto (4006 FN5)",
- .params = tuner_temic_4006fn5_multi_params,
- .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params),
- },
-
- /* 20-29 */
- [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */
- .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)",
- .params = tuner_temic_4009f_5_params,
- .count = ARRAY_SIZE(tuner_temic_4009f_5_params),
- },
- [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */
- .name = "Temic NTSC (4039 FR5)",
- .params = tuner_temic_4039fr5_params,
- .count = ARRAY_SIZE(tuner_temic_4039fr5_params),
- },
- [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */
- .name = "Temic PAL/SECAM multi (4046 FM5)",
- .params = tuner_temic_4046fm5_params,
- .count = ARRAY_SIZE(tuner_temic_4046fm5_params),
- },
- [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */
- .name = "Philips PAL_DK (FI1256 and compatibles)",
- .params = tuner_philips_pal_dk_params,
- .count = ARRAY_SIZE(tuner_philips_pal_dk_params),
- },
- [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */
- .name = "Philips PAL/SECAM multi (FQ1216ME)",
- .params = tuner_philips_fq1216me_params,
- .count = ARRAY_SIZE(tuner_philips_fq1216me_params),
- },
- [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */
- .name = "LG PAL_I+FM (TAPC-I001D)",
- .params = tuner_lg_pal_i_fm_params,
- .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params),
- },
- [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */
- .name = "LG PAL_I (TAPC-I701D)",
- .params = tuner_lg_pal_i_params,
- .count = ARRAY_SIZE(tuner_lg_pal_i_params),
- },
- [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */
- .name = "LG NTSC+FM (TPI8NSR01F)",
- .params = tuner_lg_ntsc_fm_params,
- .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params),
- },
- [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */
- .name = "LG PAL_BG+FM (TPI8PSB01D)",
- .params = tuner_lg_pal_fm_params,
- .count = ARRAY_SIZE(tuner_lg_pal_fm_params),
- },
- [TUNER_LG_PAL] = { /* LGINNOTEK PAL */
- .name = "LG PAL_BG (TPI8PSB11D)",
- .params = tuner_lg_pal_params,
- .count = ARRAY_SIZE(tuner_lg_pal_params),
- },
-
- /* 30-39 */
- [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */
- .name = "Temic PAL* auto + FM (4009 FN5)",
- .params = tuner_temic_4009_fn5_multi_pal_fm_params,
- .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params),
- },
- [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */
- .name = "SHARP NTSC_JP (2U5JF5540)",
- .params = tuner_sharp_2u5jf5540_params,
- .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params),
- },
- [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */
- .name = "Samsung PAL TCPM9091PD27",
- .params = tuner_samsung_pal_tcpm9091pd27_params,
- .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params),
- },
- [TUNER_MT2032] = { /* Microtune PAL|NTSC */
- .name = "MT20xx universal",
- /* see mt20xx.c for details */ },
- [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */
- .name = "Temic PAL_BG (4106 FH5)",
- .params = tuner_temic_4106fh5_params,
- .count = ARRAY_SIZE(tuner_temic_4106fh5_params),
- },
- [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */
- .name = "Temic PAL_DK/SECAM_L (4012 FY5)",
- .params = tuner_temic_4012fy5_params,
- .count = ARRAY_SIZE(tuner_temic_4012fy5_params),
- },
- [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */
- .name = "Temic NTSC (4136 FY5)",
- .params = tuner_temic_4136_fy5_params,
- .count = ARRAY_SIZE(tuner_temic_4136_fy5_params),
- },
- [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */
- .name = "LG PAL (newer TAPC series)",
- .params = tuner_lg_pal_new_tapc_params,
- .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params),
- },
- [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */
- .name = "Philips PAL/SECAM multi (FM1216ME MK3)",
- .params = tuner_fm1216me_mk3_params,
- .count = ARRAY_SIZE(tuner_fm1216me_mk3_params),
- },
- [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */
- .name = "LG NTSC (newer TAPC series)",
- .params = tuner_lg_ntsc_new_tapc_params,
- .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params),
- },
-
- /* 40-49 */
- [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */
- .name = "HITACHI V7-J180AT",
- .params = tuner_hitachi_ntsc_params,
- .count = ARRAY_SIZE(tuner_hitachi_ntsc_params),
- },
- [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */
- .name = "Philips PAL_MK (FI1216 MK)",
- .params = tuner_philips_pal_mk_params,
- .count = ARRAY_SIZE(tuner_philips_pal_mk_params),
- },
- [TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */
- .name = "Philips FCV1236D ATSC/NTSC dual in",
- .params = tuner_philips_fcv1236d_params,
- .count = ARRAY_SIZE(tuner_philips_fcv1236d_params),
- .min = 16 * 53.00,
- .max = 16 * 803.00,
- .stepsize = 62500,
- },
- [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
- .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
- .params = tuner_fm1236_mk3_params,
- .count = ARRAY_SIZE(tuner_fm1236_mk3_params),
- },
- [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */
- .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)",
- .params = tuner_philips_4in1_params,
- .count = ARRAY_SIZE(tuner_philips_4in1_params),
- },
- [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */
- .name = "Microtune 4049 FM5",
- .params = tuner_microtune_4049_fm5_params,
- .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params),
- },
- [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */
- .name = "Panasonic VP27s/ENGE4324D",
- .params = tuner_panasonic_vp27_params,
- .count = ARRAY_SIZE(tuner_panasonic_vp27_params),
- },
- [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */
- .name = "LG NTSC (TAPE series)",
- .params = tuner_fm1236_mk3_params,
- .count = ARRAY_SIZE(tuner_fm1236_mk3_params),
- },
- [TUNER_TNF_8831BGFF] = { /* Philips PAL */
- .name = "Tenna TNF 8831 BGFF)",
- .params = tuner_tnf_8831bgff_params,
- .count = ARRAY_SIZE(tuner_tnf_8831bgff_params),
- },
- [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */
- .name = "Microtune 4042 FI5 ATSC/NTSC dual in",
- .params = tuner_microtune_4042fi5_params,
- .count = ARRAY_SIZE(tuner_microtune_4042fi5_params),
- .min = 16 * 57.00,
- .max = 16 * 858.00,
- .stepsize = 62500,
- },
-
- /* 50-59 */
- [TUNER_TCL_2002N] = { /* TCL NTSC */
- .name = "TCL 2002N",
- .params = tuner_tcl_2002n_params,
- .count = ARRAY_SIZE(tuner_tcl_2002n_params),
- },
- [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */
- .name = "Philips PAL/SECAM_D (FM 1256 I-H3)",
- .params = tuner_philips_fm1256_ih3_params,
- .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params),
- },
- [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */
- .name = "Thomson DTT 7610 (ATSC/NTSC)",
- .params = tuner_thomson_dtt7610_params,
- .count = ARRAY_SIZE(tuner_thomson_dtt7610_params),
- .min = 16 * 44.00,
- .max = 16 * 958.00,
- .stepsize = 62500,
- },
- [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
- .name = "Philips FQ1286",
- .params = tuner_philips_fq1286_params,
- .count = ARRAY_SIZE(tuner_philips_fq1286_params),
- },
- [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
- .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271",
- /* see tda8290.c for details */ },
- [TUNER_TCL_2002MB] = { /* TCL PAL */
- .name = "TCL 2002MB",
- .params = tuner_tcl_2002mb_params,
- .count = ARRAY_SIZE(tuner_tcl_2002mb_params),
- },
- [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */
- .name = "Philips PAL/SECAM multi (FQ1216AME MK4)",
- .params = tuner_philips_fq1216ame_mk4_params,
- .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params),
- },
- [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */
- .name = "Philips FQ1236A MK4",
- .params = tuner_philips_fq1236a_mk4_params,
- .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params),
- },
- [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */
- .name = "Ymec TVision TVF-8531MF/8831MF/8731MF",
- .params = tuner_ymec_tvf_8531mf_params,
- .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params),
- },
- [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */
- .name = "Ymec TVision TVF-5533MF",
- .params = tuner_ymec_tvf_5533mf_params,
- .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params),
- },
-
- /* 60-69 */
- [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */
- /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
- .name = "Thomson DTT 761X (ATSC/NTSC)",
- .params = tuner_thomson_dtt761x_params,
- .count = ARRAY_SIZE(tuner_thomson_dtt761x_params),
- .min = 16 * 57.00,
- .max = 16 * 863.00,
- .stepsize = 62500,
- .initdata = tua603x_agc103,
- },
- [TUNER_TENA_9533_DI] = { /* Philips PAL */
- .name = "Tena TNF9533-D/IF/TNF9533-B/DF",
- .params = tuner_tena_9533_di_params,
- .count = ARRAY_SIZE(tuner_tena_9533_di_params),
- },
- [TUNER_TEA5767] = { /* Philips RADIO */
- .name = "Philips TEA5767HN FM Radio",
- /* see tea5767.c for details */
- },
- [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */
- .name = "Philips FMD1216ME MK3 Hybrid Tuner",
- .params = tuner_philips_fmd1216me_mk3_params,
- .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
- .min = 16 * 50.87,
- .max = 16 * 858.00,
- .stepsize = 166667,
- .initdata = tua603x_agc112,
- .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
- },
- [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
- .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */
- .params = tuner_lg_tdvs_h06xf_params,
- .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
- .min = 16 * 54.00,
- .max = 16 * 863.00,
- .stepsize = 62500,
- .initdata = tua603x_agc103,
- },
- [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
- .name = "Ymec TVF66T5-B/DFF",
- .params = tuner_ymec_tvf66t5_b_dff_params,
- .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params),
- },
- [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */
- .name = "LG TALN series",
- .params = tuner_lg_taln_params,
- .count = ARRAY_SIZE(tuner_lg_taln_params),
- },
- [TUNER_PHILIPS_TD1316] = { /* Philips PAL */
- .name = "Philips TD1316 Hybrid Tuner",
- .params = tuner_philips_td1316_params,
- .count = ARRAY_SIZE(tuner_philips_td1316_params),
- .min = 16 * 87.00,
- .max = 16 * 895.00,
- .stepsize = 166667,
- },
- [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
- .name = "Philips TUV1236D ATSC/NTSC dual in",
- .params = tuner_tuv1236d_params,
- .count = ARRAY_SIZE(tuner_tuv1236d_params),
- .min = 16 * 54.00,
- .max = 16 * 864.00,
- .stepsize = 62500,
- },
- [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */
- .name = "Tena TNF 5335 and similar models",
- .params = tuner_tnf_5335mf_params,
- .count = ARRAY_SIZE(tuner_tnf_5335mf_params),
- },
-
- /* 70-79 */
- [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */
- .name = "Samsung TCPN 2121P30A",
- .params = tuner_samsung_tcpn_2121p30a_params,
- .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params),
- },
- [TUNER_XC2028] = { /* Xceive 2028 */
- .name = "Xceive xc2028/xc3028 tuner",
- /* see tuner-xc2028.c for details */
- },
- [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
- .name = "Thomson FE6600",
- .params = tuner_thomson_fe6600_params,
- .count = ARRAY_SIZE(tuner_thomson_fe6600_params),
- .min = 16 * 44.25,
- .max = 16 * 858.00,
- .stepsize = 166667,
- },
- [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
- .name = "Samsung TCPG 6121P30A",
- .params = tuner_samsung_tcpg_6121p30a_params,
- .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
- },
- [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
- This chip is part of some modern tuners */
- .name = "Philips TDA988[5,6,7] IF PLL Demodulator",
- /* see tda9887.c for details */
- },
- [TUNER_TEA5761] = { /* Philips RADIO */
- .name = "Philips TEA5761 FM Radio",
- /* see tea5767.c for details */
- },
- [TUNER_XC5000] = { /* Xceive 5000 */
- .name = "Xceive 5000 tuner",
- /* see xc5000.c for details */
- },
-};
-EXPORT_SYMBOL(tuners);
-
-unsigned const int tuner_count = ARRAY_SIZE(tuners);
-EXPORT_SYMBOL(tuner_count);
-
-MODULE_DESCRIPTION("Simple tuner device type database");
-MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
-MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/tuner-xc2028-types.h b/linux/drivers/media/video/tuner-xc2028-types.h
deleted file mode 100644
index d0057fbf0..000000000
--- a/linux/drivers/media/video/tuner-xc2028-types.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* tuner-xc2028_types
- *
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-/* xc3028 firmware types */
-
-/* BASE firmware should be loaded before any other firmware */
-#define BASE (1<<0)
-#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1)
-
-/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
-#define F8MHZ (1<<1)
-
-/* Multichannel Television Sound (MTS)
- Those firmwares are capable of using xc2038 DSP to decode audio and
- produce a baseband audio output on some pins of the chip.
- There are MTS firmwares for the most used video standards. It should be
- required to use MTS firmwares, depending on the way audio is routed into
- the bridge chip
- */
-#define MTS (1<<2)
-
-/* FIXME: I have no idea what's the difference between
- D2620 and D2633 firmwares
- */
-#define D2620 (1<<3)
-#define D2633 (1<<4)
-
-/* DTV firmwares for 6, 7 and 8 MHz
- DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
- DTV8 - 8MHz - DVB-C/DVB-T
- */
-#define DTV6 (1 << 5)
-#define QAM (1 << 6)
-#define DTV7 (1<<7)
-#define DTV78 (1<<8)
-#define DTV8 (1<<9)
-
-#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC)
-
-/* There's a FM | BASE firmware + FM specific firmware (std=0) */
-#define FM (1<<10)
-
-#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD)
-
-/* Applies only for FM firmware
- Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
- */
-#define INPUT1 (1<<11)
-
-
-/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
- and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
- There are variants both with and without NOGD
- */
-#define LCD (1<<12)
-
-/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
- and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
- */
-#define NOGD (1<<13)
-
-/* Old firmwares were broken into init0 and init1 */
-#define INIT1 (1<<14)
-
-/* SCODE firmware selects particular behaviours */
-#define MONO (1 << 15)
-#define ATSC (1 << 16)
-#define IF (1 << 17)
-#define LG60 (1 << 18)
-#define ATI638 (1 << 19)
-#define OREN538 (1 << 20)
-#define OREN36 (1 << 21)
-#define TOYOTA388 (1 << 22)
-#define TOYOTA794 (1 << 23)
-#define DIBCOM52 (1 << 24)
-#define ZARLINK456 (1 << 25)
-#define CHINA (1 << 26)
-#define F6MHZ (1 << 27)
-#define INPUT2 (1 << 28)
-#define SCODE (1 << 29)
-
-/* This flag identifies that the scode table has a new format */
-#define HAS_IF (1 << 30)
-
-#define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
- LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \
- DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
-
-/* Newer types to be moved to videodev2.h */
-
-#define V4L2_STD_SECAM_K3 (0x04000000)
-
-/* Audio types */
-
-#define V4L2_STD_A2_A (1LL<<32)
-#define V4L2_STD_A2_B (1LL<<33)
-#define V4L2_STD_NICAM_A (1LL<<34)
-#define V4L2_STD_NICAM_B (1LL<<35)
-#define V4L2_STD_AM (1LL<<36)
-#define V4L2_STD_BTSC (1LL<<37)
-#define V4L2_STD_EIAJ (1LL<<38)
-
-#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B)
-#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
-
-/* To preserve backward compatibilty,
- (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
- */
-
-#define V4L2_STD_AUDIO (V4L2_STD_A2 | \
- V4L2_STD_NICAM | \
- V4L2_STD_AM | \
- V4L2_STD_BTSC | \
- V4L2_STD_EIAJ)
-
-/* Used standards with audio restrictions */
-
-#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A)
-#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B)
-#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
-#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
-#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2)
-#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM)
-#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM)
-#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM)
diff --git a/linux/drivers/media/video/tuner-xc2028.c b/linux/drivers/media/video/tuner-xc2028.c
deleted file mode 100644
index 0ab0cbeca..000000000
--- a/linux/drivers/media/video/tuner-xc2028.c
+++ /dev/null
@@ -1,1256 +0,0 @@
-/* tuner-xc2028
- *
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
- *
- * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
- * - frontend interface
- *
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-#include <linux/i2c.h>
-#include <asm/div64.h>
-#include <linux/firmware.h>
-#include <linux/videodev2.h>
-#include <linux/delay.h>
-#include <media/tuner.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
-#include <linux/mutex.h>
-#else
-#include <asm/semaphore.h>
-#endif
-#include "compat.h"
-#include "tuner-i2c.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#include "i2c-compat.h"
-#endif
-#include "tuner-xc2028.h"
-#include "tuner-xc2028-types.h"
-
-#include <linux/dvb/frontend.h>
-#include "dvb_frontend.h"
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
-#define strcasecmp(a, b) strnicmp(a, b, sizeof(a))
-#endif
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static char audio_std[8];
-module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
-MODULE_PARM_DESC(audio_std,
- "Audio standard. XC3028 audio decoder explicitly "
- "needs to know what audio\n"
- "standard is needed for some video standards with audio A2 or NICAM.\n"
- "The valid values are:\n"
- "A2\n"
- "A2/A\n"
- "A2/B\n"
- "NICAM\n"
- "NICAM/A\n"
- "NICAM/B\n");
-
-static char firmware_name[FIRMWARE_NAME_MAX];
-module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
-MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
- "default firmware name\n");
-
-static LIST_HEAD(xc2028_list);
-static DEFINE_MUTEX(xc2028_list_mutex);
-
-/* struct for storing firmware table */
-struct firmware_description {
- unsigned int type;
- v4l2_std_id id;
- __u16 int_freq;
- unsigned char *ptr;
- unsigned int size;
-};
-
-struct firmware_properties {
- unsigned int type;
- v4l2_std_id id;
- v4l2_std_id std_req;
- __u16 int_freq;
- unsigned int scode_table;
- int scode_nr;
-};
-
-struct xc2028_data {
- struct list_head xc2028_list;
- struct tuner_i2c_props i2c_props;
- int (*tuner_callback) (void *dev,
- int command, int arg);
- void *video_dev;
- int count;
- __u32 frequency;
-
- struct firmware_description *firm;
- int firm_size;
- __u16 firm_version;
-
- __u16 hwmodel;
- __u16 hwvers;
-
- struct xc2028_ctrl ctrl;
-
- struct firmware_properties cur_fw;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
- struct mutex lock;
-#else
- struct semaphore lock;
-#endif
-};
-
-#define i2c_send(priv, buf, size) ({ \
- int _rc; \
- _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \
- if (size != _rc) \
- tuner_info("i2c output error: rc = %d (should be %d)\n",\
- _rc, (int)size); \
- _rc; \
-})
-
-#define i2c_rcv(priv, buf, size) ({ \
- int _rc; \
- _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \
- if (size != _rc) \
- tuner_err("i2c input error: rc = %d (should be %d)\n", \
- _rc, (int)size); \
- _rc; \
-})
-
-#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \
- int _rc; \
- _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \
- ibuf, isize); \
- if (isize != _rc) \
- tuner_err("i2c input error: rc = %d (should be %d)\n", \
- _rc, (int)isize); \
- _rc; \
-})
-
-#define send_seq(priv, data...) ({ \
- static u8 _val[] = data; \
- int _rc; \
- if (sizeof(_val) != \
- (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \
- _val, sizeof(_val)))) { \
- tuner_err("Error on line %d: %d\n", __LINE__, _rc); \
- } else \
- msleep(10); \
- _rc; \
-})
-
-static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
-{
- unsigned char buf[2];
- unsigned char ibuf[2];
-
- tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
-
- buf[0] = reg >> 8;
- buf[1] = (unsigned char) reg;
-
- if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
- return -EIO;
-
- *val = (ibuf[1]) | (ibuf[0] << 8);
- return 0;
-}
-
-#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0)
-static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
-{
- if (type & BASE)
- printk("BASE ");
- if (type & INIT1)
- printk("INIT1 ");
- if (type & F8MHZ)
- printk("F8MHZ ");
- if (type & MTS)
- printk("MTS ");
- if (type & D2620)
- printk("D2620 ");
- if (type & D2633)
- printk("D2633 ");
- if (type & DTV6)
- printk("DTV6 ");
- if (type & QAM)
- printk("QAM ");
- if (type & DTV7)
- printk("DTV7 ");
- if (type & DTV78)
- printk("DTV78 ");
- if (type & DTV8)
- printk("DTV8 ");
- if (type & FM)
- printk("FM ");
- if (type & INPUT1)
- printk("INPUT1 ");
- if (type & LCD)
- printk("LCD ");
- if (type & NOGD)
- printk("NOGD ");
- if (type & MONO)
- printk("MONO ");
- if (type & ATSC)
- printk("ATSC ");
- if (type & IF)
- printk("IF ");
- if (type & LG60)
- printk("LG60 ");
- if (type & ATI638)
- printk("ATI638 ");
- if (type & OREN538)
- printk("OREN538 ");
- if (type & OREN36)
- printk("OREN36 ");
- if (type & TOYOTA388)
- printk("TOYOTA388 ");
- if (type & TOYOTA794)
- printk("TOYOTA794 ");
- if (type & DIBCOM52)
- printk("DIBCOM52 ");
- if (type & ZARLINK456)
- printk("ZARLINK456 ");
- if (type & CHINA)
- printk("CHINA ");
- if (type & F6MHZ)
- printk("F6MHZ ");
- if (type & INPUT2)
- printk("INPUT2 ");
- if (type & SCODE)
- printk("SCODE ");
- if (type & HAS_IF)
- printk("HAS_IF_%d ", int_freq);
-}
-
-static v4l2_std_id parse_audio_std_option(void)
-{
- if (strcasecmp(audio_std, "A2") == 0)
- return V4L2_STD_A2;
- if (strcasecmp(audio_std, "A2/A") == 0)
- return V4L2_STD_A2_A;
- if (strcasecmp(audio_std, "A2/B") == 0)
- return V4L2_STD_A2_B;
- if (strcasecmp(audio_std, "NICAM") == 0)
- return V4L2_STD_NICAM;
- if (strcasecmp(audio_std, "NICAM/A") == 0)
- return V4L2_STD_NICAM_A;
- if (strcasecmp(audio_std, "NICAM/B") == 0)
- return V4L2_STD_NICAM_B;
-
- return 0;
-}
-
-static void free_firmware(struct xc2028_data *priv)
-{
- int i;
-
- if (!priv->firm)
- return;
-
- for (i = 0; i < priv->firm_size; i++)
- kfree(priv->firm[i].ptr);
-
- kfree(priv->firm);
-
- priv->firm = NULL;
- priv->firm_size = 0;
-
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-}
-
-static int load_all_firmwares(struct dvb_frontend *fe)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- const struct firmware *fw = NULL;
- unsigned char *p, *endp;
- int rc = 0;
- int n, n_array;
- char name[33];
- char *fname;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- if (!firmware_name[0])
- fname = priv->ctrl.fname;
- else
- fname = firmware_name;
-
- tuner_dbg("Reading firmware %s\n", fname);
- rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
- if (rc < 0) {
- if (rc == -ENOENT)
- tuner_err("Error: firmware %s not found.\n",
- fname);
- else
- tuner_err("Error %d while requesting firmware %s \n",
- rc, fname);
-
- return rc;
- }
- p = fw->data;
- endp = p + fw->size;
-
- if (fw->size < sizeof(name) - 1 + 2 + 2) {
- tuner_err("Error: firmware file %s has invalid size!\n",
- fname);
- goto corrupt;
- }
-
- memcpy(name, p, sizeof(name) - 1);
- name[sizeof(name) - 1] = 0;
- p += sizeof(name) - 1;
-
- priv->firm_version = le16_to_cpu(*(__u16 *) p);
- p += 2;
-
- n_array = le16_to_cpu(*(__u16 *) p);
- p += 2;
-
- tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
- n_array, fname, name,
- priv->firm_version >> 8, priv->firm_version & 0xff);
-
- priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
- if (priv->firm == NULL) {
- tuner_err("Not enough memory to load firmware file.\n");
- rc = -ENOMEM;
- goto err;
- }
- priv->firm_size = n_array;
-
- n = -1;
- while (p < endp) {
- __u32 type, size;
- v4l2_std_id id;
- __u16 int_freq = 0;
-
- n++;
- if (n >= n_array) {
- tuner_err("More firmware images in file than "
- "were expected!\n");
- goto corrupt;
- }
-
- /* Checks if there's enough bytes to read */
- if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
- tuner_err("Firmware header is incomplete!\n");
- goto corrupt;
- }
-
- type = le32_to_cpu(*(__u32 *) p);
- p += sizeof(type);
-
- id = le64_to_cpu(*(v4l2_std_id *) p);
- p += sizeof(id);
-
- if (type & HAS_IF) {
- int_freq = le16_to_cpu(*(__u16 *) p);
- p += sizeof(int_freq);
- }
-
- size = le32_to_cpu(*(__u32 *) p);
- p += sizeof(size);
-
- if ((!size) || (size + p > endp)) {
- tuner_err("Firmware type ");
- dump_firm_type(type);
- printk("(%x), id %llx is corrupted "
- "(size=%d, expected %d)\n",
- type, (unsigned long long)id,
- (unsigned)(endp - p), size);
- goto corrupt;
- }
-
- priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
- if (priv->firm[n].ptr == NULL) {
- tuner_err("Not enough memory to load firmware file.\n");
- rc = -ENOMEM;
- goto err;
- }
- tuner_dbg("Reading firmware type ");
- if (debug) {
- dump_firm_type_and_int_freq(type, int_freq);
- printk("(%x), id %llx, size=%d.\n",
- type, (unsigned long long)id, size);
- }
-
- memcpy(priv->firm[n].ptr, p, size);
- priv->firm[n].type = type;
- priv->firm[n].id = id;
- priv->firm[n].size = size;
- priv->firm[n].int_freq = int_freq;
-
- p += size;
- }
-
- if (n + 1 != priv->firm_size) {
- tuner_err("Firmware file is incomplete!\n");
- goto corrupt;
- }
-
- goto done;
-
-corrupt:
- rc = -EINVAL;
- tuner_err("Error: firmware file is corrupted!\n");
-
-err:
- tuner_info("Releasing partially loaded firmware file.\n");
- free_firmware(priv);
-
-done:
- release_firmware(fw);
- if (rc == 0)
- tuner_dbg("Firmware files loaded.\n");
-
- return rc;
-}
-
-static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int i, best_i = -1, best_nr_matches = 0;
- unsigned int ign_firm_type_mask = 0;
-
- tuner_dbg("%s called, want type=", __FUNCTION__);
- if (debug) {
- dump_firm_type(type);
- printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
- }
-
- if (!priv->firm) {
- tuner_err("Error! firmware not loaded\n");
- return -EINVAL;
- }
-
- if (((type & ~SCODE) == 0) && (*id == 0))
- *id = V4L2_STD_PAL;
-
- if (type & BASE)
- type &= BASE_TYPES;
- else if (type & SCODE) {
- type &= SCODE_TYPES;
- ign_firm_type_mask = HAS_IF;
- } else if (type & DTV_TYPES)
- type &= DTV_TYPES;
- else if (type & STD_SPECIFIC_TYPES)
- type &= STD_SPECIFIC_TYPES;
-
- /* Seek for exact match */
- for (i = 0; i < priv->firm_size; i++) {
- if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) &&
- (*id == priv->firm[i].id))
- goto found;
- }
-
- /* Seek for generic video standard match */
- for (i = 0; i < priv->firm_size; i++) {
- v4l2_std_id match_mask;
- int nr_matches;
-
- if (type != (priv->firm[i].type & ~ign_firm_type_mask))
- continue;
-
- match_mask = *id & priv->firm[i].id;
- if (!match_mask)
- continue;
-
- if ((*id & match_mask) == *id)
- goto found; /* Supports all the requested standards */
-
- nr_matches = hweight64(match_mask);
- if (nr_matches > best_nr_matches) {
- best_nr_matches = nr_matches;
- best_i = i;
- }
- }
-
- if (best_nr_matches > 0) {
- tuner_dbg("Selecting best matching firmware (%d bits) for "
- "type=", best_nr_matches);
- dump_firm_type(type);
- printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
- i = best_i;
- goto found;
- }
-
- /*FIXME: Would make sense to seek for type "hint" match ? */
-
- i = -ENOENT;
- goto ret;
-
-found:
- *id = priv->firm[i].id;
-
-ret:
- tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
- if (debug) {
- dump_firm_type(type);
- printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
- }
- return i;
-}
-
-static int load_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int pos, rc;
- unsigned char *p, *endp, buf[priv->ctrl.max_len];
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- pos = seek_firmware(fe, type, id);
- if (pos < 0)
- return pos;
-
- tuner_info("Loading firmware for type=");
- dump_firm_type(priv->firm[pos].type);
- printk("(%x), id %016llx.\n", priv->firm[pos].type,
- (unsigned long long)*id);
-
- p = priv->firm[pos].ptr;
- endp = p + priv->firm[pos].size;
-
- while (p < endp) {
- __u16 size;
-
- /* Checks if there's enough bytes to read */
- if (p + sizeof(size) > endp) {
- tuner_err("Firmware chunk size is wrong\n");
- return -EINVAL;
- }
-
- size = le16_to_cpu(*(__u16 *) p);
- p += sizeof(size);
-
- if (size == 0xffff)
- return 0;
-
- if (!size) {
- /* Special callback command received */
- rc = priv->tuner_callback(priv->video_dev,
- XC2028_TUNER_RESET, 0);
- if (rc < 0) {
- tuner_err("Error at RESET code %d\n",
- (*p) & 0x7f);
- return -EINVAL;
- }
- continue;
- }
- if (size >= 0xff00) {
- switch (size) {
- case 0xff00:
- rc = priv->tuner_callback(priv->video_dev,
- XC2028_RESET_CLK, 0);
- if (rc < 0) {
- tuner_err("Error at RESET code %d\n",
- (*p) & 0x7f);
- return -EINVAL;
- }
- break;
- default:
- tuner_info("Invalid RESET code %d\n",
- size & 0x7f);
- return -EINVAL;
-
- }
- continue;
- }
-
- /* Checks for a sleep command */
- if (size & 0x8000) {
- msleep(size & 0x7fff);
- continue;
- }
-
- if ((size + p > endp)) {
- tuner_err("missing bytes: need %d, have %d\n",
- size, (int)(endp - p));
- return -EINVAL;
- }
-
- buf[0] = *p;
- p++;
- size--;
-
- /* Sends message chunks */
- while (size > 0) {
- int len = (size < priv->ctrl.max_len - 1) ?
- size : priv->ctrl.max_len - 1;
-
- memcpy(buf + 1, p, len);
-
- rc = i2c_send(priv, buf, len + 1);
- if (rc < 0) {
- tuner_err("%d returned from send\n", rc);
- return -EINVAL;
- }
-
- p += len;
- size -= len;
- }
- }
- return 0;
-}
-
-static int load_scode(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id, __u16 int_freq, int scode)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int pos, rc;
- unsigned char *p;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- if (!int_freq) {
- pos = seek_firmware(fe, type, id);
- if (pos < 0)
- return pos;
- } else {
- for (pos = 0; pos < priv->firm_size; pos++) {
- if ((priv->firm[pos].int_freq == int_freq) &&
- (priv->firm[pos].type & HAS_IF))
- break;
- }
- if (pos == priv->firm_size)
- return -ENOENT;
- }
-
- p = priv->firm[pos].ptr;
-
- if (priv->firm[pos].type & HAS_IF) {
- if (priv->firm[pos].size != 12 * 16 || scode >= 16)
- return -EINVAL;
- p += 12 * scode;
- } else {
- /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
- * has a 2-byte size header in the firmware format. */
- if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
- le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
- return -EINVAL;
- p += 14 * scode + 2;
- }
-
- tuner_info("Loading SCODE for type=");
- dump_firm_type_and_int_freq(priv->firm[pos].type,
- priv->firm[pos].int_freq);
- printk("(%x), id %016llx.\n", priv->firm[pos].type,
- (unsigned long long)*id);
-
- if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
- else
- rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
- if (rc < 0)
- return -EIO;
-
- rc = i2c_send(priv, p, 12);
- if (rc < 0)
- return -EIO;
-
- rc = send_seq(priv, {0x00, 0x8c});
- if (rc < 0)
- return -EIO;
-
- return 0;
-}
-
-static int check_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id std, __u16 int_freq)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- struct firmware_properties new_fw;
- int rc = 0, is_retry = 0;
- u16 version, hwmodel;
- v4l2_std_id std0;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- if (!priv->firm) {
- if (!priv->ctrl.fname) {
- tuner_info("xc2028/3028 firmware name not set!\n");
- return -EINVAL;
- }
-
- rc = load_all_firmwares(fe);
- if (rc < 0)
- return rc;
- }
-
- if (priv->ctrl.mts && !(type & FM))
- type |= MTS;
-
-retry:
- new_fw.type = type;
- new_fw.id = std;
- new_fw.std_req = std;
- new_fw.scode_table = SCODE | priv->ctrl.scode_table;
- new_fw.scode_nr = 0;
- new_fw.int_freq = int_freq;
-
- tuner_dbg("checking firmware, user requested type=");
- if (debug) {
- dump_firm_type(new_fw.type);
- printk("(%x), id %016llx, ", new_fw.type,
- (unsigned long long)new_fw.std_req);
- if (!int_freq) {
- printk("scode_tbl ");
- dump_firm_type(priv->ctrl.scode_table);
- printk("(%x), ", priv->ctrl.scode_table);
- } else
- printk("int_freq %d, ", new_fw.int_freq);
- printk("scode_nr %d\n", new_fw.scode_nr);
- }
-
- /* No need to reload base firmware if it matches */
- if (((BASE | new_fw.type) & BASE_TYPES) ==
- (priv->cur_fw.type & BASE_TYPES)) {
- tuner_dbg("BASE firmware not changed.\n");
- goto skip_base;
- }
-
- /* Updating BASE - forget about all currently loaded firmware */
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
-
- /* Reset is needed before loading firmware */
- rc = priv->tuner_callback(priv->video_dev,
- XC2028_TUNER_RESET, 0);
- if (rc < 0)
- goto fail;
-
- /* BASE firmwares are all std0 */
- std0 = 0;
- rc = load_firmware(fe, BASE | new_fw.type, &std0);
- if (rc < 0) {
- tuner_err("Error %d while loading base firmware\n",
- rc);
- goto fail;
- }
-
- /* Load INIT1, if needed */
- tuner_dbg("Load init1 firmware, if exists\n");
-
- rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
- if (rc == -ENOENT)
- rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
- &std0);
- if (rc < 0 && rc != -ENOENT) {
- tuner_err("Error %d while loading init1 firmware\n",
- rc);
- goto fail;
- }
-
-skip_base:
- /*
- * No need to reload standard specific firmware if base firmware
- * was not reloaded and requested video standards have not changed.
- */
- if (priv->cur_fw.type == (BASE | new_fw.type) &&
- priv->cur_fw.std_req == std) {
- tuner_dbg("Std-specific firmware already loaded.\n");
- goto skip_std_specific;
- }
-
- /* Reloading std-specific firmware forces a SCODE update */
- priv->cur_fw.scode_table = 0;
-
- rc = load_firmware(fe, new_fw.type, &new_fw.id);
- if (rc == -ENOENT)
- rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
-
- if (rc < 0)
- goto fail;
-
-skip_std_specific:
- if (priv->cur_fw.scode_table == new_fw.scode_table &&
- priv->cur_fw.scode_nr == new_fw.scode_nr) {
- tuner_dbg("SCODE firmware already loaded.\n");
- goto check_device;
- }
-
- if (new_fw.type & FM)
- goto check_device;
-
- /* Load SCODE firmware, if exists */
- tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
-
- rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
- new_fw.int_freq, new_fw.scode_nr);
-
-check_device:
- if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
- xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
- tuner_err("Unable to read tuner registers.\n");
- goto fail;
- }
-
- tuner_info("Device is Xceive %d version %d.%d, "
- "firmware version %d.%d\n",
- hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
- (version & 0xf0) >> 4, version & 0xf);
-
- /* Check firmware version against what we downloaded. */
- if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
- tuner_err("Incorrect readback of firmware version.\n");
- goto fail;
- }
-
- /* Check that the tuner hardware model remains consistent over time. */
- if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
- priv->hwmodel = hwmodel;
- priv->hwvers = version & 0xff00;
- } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
- priv->hwvers != (version & 0xff00)) {
- tuner_err("Read invalid device hardware information - tuner "
- "hung?\n");
- goto fail;
- }
-
- memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
-
- /*
- * By setting BASE in cur_fw.type only after successfully loading all
- * firmwares, we can:
- * 1. Identify that BASE firmware with type=0 has been loaded;
- * 2. Tell whether BASE firmware was just changed the next time through.
- */
- priv->cur_fw.type |= BASE;
-
- return 0;
-
-fail:
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
- if (!is_retry) {
- msleep(50);
- is_retry = 1;
- tuner_dbg("Retrying firmware load\n");
- goto retry;
- }
-
- if (rc == -ENOENT)
- rc = -EINVAL;
- return rc;
-}
-
-static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- u16 frq_lock, signal = 0;
- int rc;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- mutex_lock(&priv->lock);
-
- /* Sync Lock Indicator */
- rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
- if (rc < 0 || frq_lock == 0)
- goto ret;
-
- /* Frequency is locked. Return signal quality */
-
- /* Get SNR of the video signal */
- rc = xc2028_get_reg(priv, 0x0040, &signal);
- if (rc < 0)
- signal = -frq_lock;
-
-ret:
- mutex_unlock(&priv->lock);
-
- *strength = signal;
-
- return rc;
-}
-
-#define DIV 15625
-
-static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
- enum tuner_mode new_mode,
- unsigned int type,
- v4l2_std_id std,
- u16 int_freq)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int rc = -EINVAL;
- unsigned char buf[4];
- u32 div, offset = 0;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- mutex_lock(&priv->lock);
-
- tuner_dbg("should set frequency %d kHz\n", freq / 1000);
-
- if (check_firmware(fe, type, std, int_freq) < 0)
- goto ret;
-
- /* On some cases xc2028 can disable video output, if
- * very weak signals are received. By sending a soft
- * reset, this is re-enabled. So, it is better to always
- * send a soft reset before changing channels, to be sure
- * that xc2028 will be in a safe state.
- * Maybe this might also be needed for DTV.
- */
- if (new_mode == T_ANALOG_TV) {
- rc = send_seq(priv, {0x00, 0x00});
- } else if (priv->cur_fw.type & ATSC) {
- offset = 1750000;
- } else {
- offset = 2750000;
- /*
- * We must adjust the offset by 500kHz in two cases in order
- * to correctly center the IF output:
- * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
- * selected and a 7MHz channel is tuned;
- * 2) When tuning a VHF channel with DTV78 firmware.
- */
- if (((priv->cur_fw.type & DTV7) &&
- (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
- ((priv->cur_fw.type & DTV78) && freq < 470000000))
- offset -= 500000;
- }
-
- div = (freq - offset + DIV / 2) / DIV;
-
- /* CMD= Set frequency */
- if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00});
- else
- rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00});
- if (rc < 0)
- goto ret;
-
- /* Return code shouldn't be checked.
- The reset CLK is needed only with tm6000.
- Driver should work fine even if this fails.
- */
- priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
-
- msleep(10);
-
- buf[0] = 0xff & (div >> 24);
- buf[1] = 0xff & (div >> 16);
- buf[2] = 0xff & (div >> 8);
- buf[3] = 0xff & (div);
-
- rc = i2c_send(priv, buf, sizeof(buf));
- if (rc < 0)
- goto ret;
- msleep(100);
-
- priv->frequency = freq;
-
- tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n",
- buf[0], buf[1], buf[2], buf[3],
- freq / 1000000, (freq % 1000000) / 1000);
-
- rc = 0;
-
-ret:
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
-static int xc2028_set_analog_freq(struct dvb_frontend *fe,
- struct analog_parameters *p)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- unsigned int type=0;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- if (p->mode == V4L2_TUNER_RADIO) {
- type |= FM;
- if (priv->ctrl.input1)
- type |= INPUT1;
- return generic_set_freq(fe, (625l * p->frequency) / 10,
- T_ANALOG_TV, type, 0, 0);
- }
-
- /* if std is not defined, choose one */
- if (!p->std)
- p->std = V4L2_STD_MN;
-
- /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
- if (!(p->std & V4L2_STD_MN))
- type |= F8MHZ;
-
- /* Add audio hack to std mask */
- p->std |= parse_audio_std_option();
-
- return generic_set_freq(fe, 62500l * p->frequency,
- T_ANALOG_TV, type, p->std, 0);
-}
-
-static int xc2028_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- unsigned int type=0;
- fe_bandwidth_t bw = BANDWIDTH_8_MHZ;
- u16 demod = 0;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- if (priv->ctrl.d2633)
- type |= D2633;
- else
- type |= D2620;
-
- switch(fe->ops.info.type) {
- case FE_OFDM:
- bw = p->u.ofdm.bandwidth;
- break;
- case FE_QAM:
- tuner_info("WARN: There are some reports that "
- "QAM 6 MHz doesn't work.\n"
- "If this works for you, please report by "
- "e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
- bw = BANDWIDTH_6_MHZ;
- type |= QAM;
- break;
- case FE_ATSC:
- bw = BANDWIDTH_6_MHZ;
- /* The only ATSC firmware (at least on v2.7) is D2633,
- so overrides ctrl->d2633 */
- type |= ATSC| D2633;
- type &= ~D2620;
- break;
- /* DVB-S is not supported */
- default:
- return -EINVAL;
- }
-
- switch (bw) {
- case BANDWIDTH_8_MHZ:
- if (p->frequency < 470000000)
- priv->ctrl.vhfbw7 = 0;
- else
- priv->ctrl.uhfbw8 = 1;
- type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
- type |= F8MHZ;
- break;
- case BANDWIDTH_7_MHZ:
- if (p->frequency < 470000000)
- priv->ctrl.vhfbw7 = 1;
- else
- priv->ctrl.uhfbw8 = 0;
- type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
- type |= F8MHZ;
- break;
- case BANDWIDTH_6_MHZ:
- type |= DTV6;
- priv->ctrl.vhfbw7 = 0;
- priv->ctrl.uhfbw8 = 0;
- break;
- default:
- tuner_err("error: bandwidth not supported.\n");
- };
-
- /* All S-code tables need a 200kHz shift */
- if (priv->ctrl.demod)
- demod = priv->ctrl.demod + 200;
-
- return generic_set_freq(fe, p->frequency,
- T_DIGITAL_TV, type, 0, demod);
-}
-
-static int xc2028_sleep(struct dvb_frontend *fe)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int rc = 0;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- mutex_lock(&priv->lock);
-
- if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
- else
- rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
-
- priv->cur_fw.type = 0; /* need firmware reload */
-
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
-
-static int xc2028_dvb_release(struct dvb_frontend *fe)
-{
- struct xc2028_data *priv = fe->tuner_priv;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- mutex_lock(&xc2028_list_mutex);
-
- priv->count--;
-
- if (!priv->count) {
- list_del(&priv->xc2028_list);
-
- kfree(priv->ctrl.fname);
-
- free_firmware(priv);
- kfree(priv);
- fe->tuner_priv = NULL;
- }
-
- mutex_unlock(&xc2028_list_mutex);
-
- return 0;
-}
-
-static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
- struct xc2028_data *priv = fe->tuner_priv;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- *frequency = priv->frequency;
-
- return 0;
-}
-
-static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- struct xc2028_ctrl *p = priv_cfg;
- int rc = 0;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- mutex_lock(&priv->lock);
-
- kfree(priv->ctrl.fname);
- free_firmware(priv);
-
- memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
- priv->ctrl.fname = NULL;
-
- if (p->fname) {
- priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
- if (priv->ctrl.fname == NULL)
- rc = -ENOMEM;
- }
-
- if (priv->ctrl.max_len < 9)
- priv->ctrl.max_len = 13;
-
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
-static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
- .info = {
- .name = "Xceive XC3028",
- .frequency_min = 42000000,
- .frequency_max = 864000000,
- .frequency_step = 50000,
- },
-
- .set_config = xc2028_set_config,
- .set_analog_params = xc2028_set_analog_freq,
- .release = xc2028_dvb_release,
- .get_frequency = xc2028_get_frequency,
- .get_rf_strength = xc2028_signal,
- .set_params = xc2028_set_params,
- .sleep = xc2028_sleep,
-
-#if 0
- int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
- int (*get_status)(struct dvb_frontend *fe, u32 *status);
-#endif
-};
-
-struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
- struct xc2028_config *cfg)
-{
- struct xc2028_data *priv;
- void *video_dev;
-
- if (debug)
- printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
-
- if (NULL == cfg)
- return NULL;
-
- if (!fe) {
- printk(KERN_ERR "xc2028: No frontend!\n");
- return NULL;
- }
-
- video_dev = cfg->i2c_adap->algo_data;
-
- if (debug)
- printk(KERN_DEBUG "xc2028: video_dev =%p\n", video_dev);
-
- mutex_lock(&xc2028_list_mutex);
-
- list_for_each_entry(priv, &xc2028_list, xc2028_list) {
- if (&priv->i2c_props.adap->dev == &cfg->i2c_adap->dev) {
- video_dev = NULL;
- if (debug)
- printk(KERN_DEBUG "xc2028: reusing device\n");
-
- break;
- }
- }
-
- if (video_dev) {
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (priv == NULL) {
- mutex_unlock(&xc2028_list_mutex);
- return NULL;
- }
-
- priv->i2c_props.addr = cfg->i2c_addr;
- priv->i2c_props.adap = cfg->i2c_adap;
- priv->i2c_props.name = "xc2028";
-
- priv->video_dev = video_dev;
- priv->tuner_callback = cfg->callback;
- priv->ctrl.max_len = 13;
-
- mutex_init(&priv->lock);
-
- list_add_tail(&priv->xc2028_list, &xc2028_list);
- }
-
- fe->tuner_priv = priv;
- priv->count++;
-
- if (debug)
- printk(KERN_DEBUG "xc2028: usage count is %i\n", priv->count);
-
- memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
- sizeof(xc2028_dvb_tuner_ops));
-
- tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
-
- if (cfg->ctrl)
- xc2028_set_config(fe, cfg->ctrl);
-
- mutex_unlock(&xc2028_list_mutex);
-
- return fe;
-}
-
-EXPORT_SYMBOL(xc2028_attach);
-
-MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
-MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
-MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/video/tuner-xc2028.h b/linux/drivers/media/video/tuner-xc2028.h
deleted file mode 100644
index 3eb842037..000000000
--- a/linux/drivers/media/video/tuner-xc2028.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* tuner-xc2028
- *
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-#ifndef __TUNER_XC2028_H__
-#define __TUNER_XC2028_H__
-
-#include "dvb_frontend.h"
-
-#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
-
-/* Dmoduler IF (kHz) */
-#define XC3028_FE_DEFAULT 0
-#define XC3028_FE_LG60 6000
-#define XC3028_FE_ATI638 6380
-#define XC3028_FE_OREN538 5380
-#define XC3028_FE_OREN36 3600
-#define XC3028_FE_TOYOTA388 3880
-#define XC3028_FE_TOYOTA794 7940
-#define XC3028_FE_DIBCOM52 5200
-#define XC3028_FE_ZARLINK456 4560
-#define XC3028_FE_CHINA 5200
-
-struct xc2028_ctrl {
- char *fname;
- int max_len;
- unsigned int scode_table;
- unsigned int mts :1;
- unsigned int d2633 :1;
- unsigned int input1:1;
- unsigned int vhfbw7:1;
- unsigned int uhfbw8:1;
- unsigned int demod;
-};
-
-struct xc2028_config {
- struct i2c_adapter *i2c_adap;
- u8 i2c_addr;
- void *video_dev;
- struct xc2028_ctrl *ctrl;
- int (*callback) (void *dev, int command, int arg);
-};
-
-/* xc2028 commands for callback */
-#define XC2028_TUNER_RESET 0
-#define XC2028_RESET_CLK 1
-
-#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
-extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
- struct xc2028_config *cfg);
-#else
-static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
- struct xc2028_config *cfg)
-{
- printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
- __FUNCTION__);
- return NULL;
-}
-#endif
-
-#endif /* __TUNER_XC2028_H__ */
diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c
index 9ebe13fd7..830dbe8db 100644
--- a/linux/drivers/media/video/tvaudio.c
+++ b/linux/drivers/media/video/tvaudio.c
@@ -1478,7 +1478,7 @@ static struct CHIPDESC chiplist[] = {
/* ---------------------------------------------------------------------- */
/* i2c registration */
-static int chip_probe(struct i2c_client *client)
+static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct CHIPSTATE *chip;
struct CHIPDESC *desc;
@@ -1522,7 +1522,12 @@ static int chip_probe(struct i2c_client *client)
}
/* fill required data structures */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
strcpy(client->name, desc->name);
+#else
+ if (!id)
+ strlcpy(client->name, desc->name, I2C_NAME_SIZE);
+#endif
chip->type = desc-chiplist;
chip->shadow.count = desc->registers+1;
chip->prevmode = -1;
@@ -1858,6 +1863,17 @@ static int chip_legacy_probe(struct i2c_adapter *adap)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+/* This driver supports many devices and the idea is to let the driver
+ detect which device is present. So rather than listing all supported
+ devices here, we pretend to support a single, fake device type. */
+static const struct i2c_device_id chip_id[] = {
+ { "tvaudio", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, chip_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "tvaudio",
.driverid = I2C_DRIVERID_TVAUDIO,
@@ -1865,6 +1881,9 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.probe = chip_probe,
.remove = chip_remove,
.legacy_probe = chip_legacy_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = chip_id,
+#endif
};
/*
diff --git a/linux/drivers/media/video/tveeprom.c b/linux/drivers/media/video/tveeprom.c
index 81a85035f..e38bda67a 100644
--- a/linux/drivers/media/video/tveeprom.c
+++ b/linux/drivers/media/video/tveeprom.c
@@ -323,10 +323,12 @@ audioIC[] =
{AUDIO_CHIP_INTERNAL, "CX25843"},
{AUDIO_CHIP_INTERNAL, "CX23418"},
{AUDIO_CHIP_INTERNAL, "CX23885"},
- /* 40-42 */
+ /* 40-44 */
{AUDIO_CHIP_INTERNAL, "CX23888"},
{AUDIO_CHIP_INTERNAL, "SAA7131"},
{AUDIO_CHIP_INTERNAL, "CX23887"},
+ {AUDIO_CHIP_INTERNAL, "SAA7164"},
+ {AUDIO_CHIP_INTERNAL, "AU8522"},
};
/* This list is supplied by Hauppauge. Thanks! */
@@ -345,8 +347,10 @@ static const char *decoderIC[] = {
"CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
/* 30-34 */
"CX25843", "CX23418", "NEC61153", "CX23885", "CX23888",
- /* 35-37 */
- "SAA7131", "CX25837", "CX23887"
+ /* 35-39 */
+ "SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A",
+ /* 40-42 */
+ "SAA7164", "CX23885B", "AU8522"
};
static int hasRadioTuner(int tunerType)
diff --git a/linux/drivers/media/video/tvp5150.c b/linux/drivers/media/video/tvp5150.c
index e6907db8b..7dc6623cc 100644
--- a/linux/drivers/media/video/tvp5150.c
+++ b/linux/drivers/media/video/tvp5150.c
@@ -1175,12 +1175,12 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
return 0;
c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (c == 0)
+ if (!c)
return -ENOMEM;
memcpy(c, &client_template, sizeof(struct i2c_client));
core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
- if (core == 0) {
+ if (!core) {
kfree(c);
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/upd64031a.c b/linux/drivers/media/video/upd64031a.c
index 92fc10901..c59944d72 100644
--- a/linux/drivers/media/video/upd64031a.c
+++ b/linux/drivers/media/video/upd64031a.c
@@ -209,7 +209,8 @@ static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
/* i2c implementation */
-static int upd64031a_probe(struct i2c_client *client)
+static int upd64031a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct upd64031a_state *state;
int i;
@@ -240,15 +241,25 @@ static int upd64031a_remove(struct i2c_client *client)
}
/* ----------------------------------------------------------------------- */
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
EXPORT_NO_SYMBOLS;
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id upd64031a_id[] = {
+ { "upd64031a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, upd64031a_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "upd64031a",
.driverid = I2C_DRIVERID_UPD64031A,
.command = upd64031a_command,
.probe = upd64031a_probe,
.remove = upd64031a_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = upd64031a_id,
+#endif
};
diff --git a/linux/drivers/media/video/upd64083.c b/linux/drivers/media/video/upd64083.c
index 5d441538f..3dcc5a293 100644
--- a/linux/drivers/media/video/upd64083.c
+++ b/linux/drivers/media/video/upd64083.c
@@ -186,7 +186,8 @@ static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
/* i2c implementation */
-static int upd64083_probe(struct i2c_client *client)
+static int upd64083_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct upd64083_state *state;
int i;
@@ -217,15 +218,25 @@ static int upd64083_remove(struct i2c_client *client)
}
/* ----------------------------------------------------------------------- */
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
EXPORT_NO_SYMBOLS;
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id upd64083_id[] = {
+ { "upd64083", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, upd64083_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "upd64083",
.driverid = I2C_DRIVERID_UPD64083,
.command = upd64083_command,
.probe = upd64083_probe,
.remove = upd64083_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = upd64083_id,
+#endif
};
diff --git a/linux/drivers/media/video/usbvideo/ibmcam.c b/linux/drivers/media/video/usbvideo/ibmcam.c
index 1261593cf..1afbcc147 100644
--- a/linux/drivers/media/video/usbvideo/ibmcam.c
+++ b/linux/drivers/media/video/usbvideo/ibmcam.c
@@ -802,6 +802,21 @@ static enum ParseState ibmcam_model2_320x240_parse_lines(
return scan_Continue;
}
+/*
+ * ibmcam_model3_parse_lines()
+ *
+ * | Even lines | Odd Lines |
+ * -----------------------------------|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |............|.....................|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |------------+---------------------|
+ *
+ * There is one (U, V) chroma pair for every four luma (Y) values. This
+ * function reads a pair of lines at a time and obtains missing chroma values
+ * from adjacent pixels.
+ */
static enum ParseState ibmcam_model3_parse_lines(
struct uvd *uvd,
struct usbvideo_frame *frame,
@@ -816,6 +831,7 @@ static enum ParseState ibmcam_model3_parse_lines(
const int ccm = 128; /* Color correction median - see below */
int i, u, v, rw, data_w=0, data_h=0, color_corr;
static unsigned char lineBuffer[640*3];
+ int line;
color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
@@ -869,15 +885,15 @@ static enum ParseState ibmcam_model3_parse_lines(
return scan_NextFrame;
}
- /* Make sure there's enough data for the entire line */
- len = 3 * data_w; /* <y-data> <uv-data> */
+ /* Make sure that lineBuffer can store two lines of data */
+ len = 3 * data_w; /* <y-data> <uyvy-data> */
assert(len <= sizeof(lineBuffer));
- /* Make sure there's enough data for the entire line */
+ /* Make sure there's enough data for two lines */
if (RingQueue_GetLength(&uvd->dp) < len)
return scan_Out;
- /* Suck one line out of the ring queue */
+ /* Suck two lines of data out of the ring queue */
RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
data = lineBuffer;
@@ -887,15 +903,23 @@ static enum ParseState ibmcam_model3_parse_lines(
rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
- int y, rv, gv, bv; /* RGB components */
+ /* Iterate over two lines. */
+ for (line = 0; line < 2; line++) {
+ for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+ int y;
+ int rv, gv, bv; /* RGB components */
- if (i < data_w) {
- y = data[i]; /* Luminosity is the first line */
+ if (i >= data_w) {
+ RGB24_PUTPIXEL(frame, i, rw, 0, 0, 0);
+ continue;
+ }
+
+ /* first line is YYY...Y; second is UYVY...UYVY */
+ y = data[(line == 0) ? i : (i*2 + 1)];
/* Apply static color correction */
- u = color[i*2] + hue_corr;
- v = color[i*2 + 1] + hue2_corr;
+ u = color[(i/2)*4] + hue_corr;
+ v = color[(i/2)*4 + 2] + hue2_corr;
/* Apply color correction */
if (color_corr != 0) {
@@ -903,13 +927,21 @@ static enum ParseState ibmcam_model3_parse_lines(
u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
}
- } else
- y = 0, u = v = 128;
- YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
- RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */
+
+ YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+ RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* No deinterlacing */
+ }
+
+ /* Check for the end of requested data */
+ if (rw == 0)
+ break;
+
+ /* Prepare for the second line */
+ rw--;
+ data = lineBuffer + data_w;
}
- frame->deinterlace = Deinterlace_FillEvenLines;
+ frame->deinterlace = Deinterlace_None;
/*
* Account for number of bytes that we wrote into output V4L frame.
diff --git a/linux/drivers/media/video/usbvideo/konicawc.c b/linux/drivers/media/video/usbvideo/konicawc.c
index 67f46c77f..7e2f04fb4 100644
--- a/linux/drivers/media/video/usbvideo/konicawc.c
+++ b/linux/drivers/media/video/usbvideo/konicawc.c
@@ -64,7 +64,7 @@ static struct usbvideo *cams;
static int debug;
#define DEBUG(n, format, arg...) \
if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
}
#else
#define DEBUG(n, arg...)
diff --git a/linux/drivers/media/video/usbvideo/quickcam_messenger.c b/linux/drivers/media/video/usbvideo/quickcam_messenger.c
index c6673bd58..a4f1185c0 100644
--- a/linux/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/linux/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -51,7 +51,7 @@
static int debug;
#define DEBUG(n, format, arg...) \
if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
}
#else
#define DEBUG(n, arg...)
@@ -227,7 +227,7 @@ static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
return ret;
}
-static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
+static int qcm_stv_setw(struct usb_device *dev, u16 reg, __le16 val)
{
int ret;
diff --git a/linux/drivers/media/video/usbvideo/usbvideo.c b/linux/drivers/media/video/usbvideo/usbvideo.c
index e9b305a77..f1aafd97d 100644
--- a/linux/drivers/media/video/usbvideo/usbvideo.c
+++ b/linux/drivers/media/video/usbvideo/usbvideo.c
@@ -525,11 +525,11 @@ void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
static int num_pass;
if (uvd == NULL) {
- err("%s: uvd == NULL", __FUNCTION__);
+ err("%s: uvd == NULL", __func__);
return;
}
if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
- err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
+ err("%s: uvd->curframe=%d.", __func__, uvd->curframe);
return;
}
@@ -630,15 +630,15 @@ EXPORT_SYMBOL(usbvideo_HexDump);
static int usbvideo_ClientIncModCount(struct uvd *uvd)
{
if (uvd == NULL) {
- err("%s: uvd == NULL", __FUNCTION__);
+ err("%s: uvd == NULL", __func__);
return -EINVAL;
}
if (uvd->handle == NULL) {
- err("%s: uvd->handle == NULL", __FUNCTION__);
+ err("%s: uvd->handle == NULL", __func__);
return -EINVAL;
}
if (!try_module_get(uvd->handle->md_module)) {
- err("%s: try_module_get() == 0", __FUNCTION__);
+ err("%s: try_module_get() == 0", __func__);
return -ENODEV;
}
return 0;
@@ -647,15 +647,15 @@ static int usbvideo_ClientIncModCount(struct uvd *uvd)
static void usbvideo_ClientDecModCount(struct uvd *uvd)
{
if (uvd == NULL) {
- err("%s: uvd == NULL", __FUNCTION__);
+ err("%s: uvd == NULL", __func__);
return;
}
if (uvd->handle == NULL) {
- err("%s: uvd->handle == NULL", __FUNCTION__);
+ err("%s: uvd->handle == NULL", __func__);
return;
}
if (uvd->handle->md_module == NULL) {
- err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
+ err("%s: uvd->handle->md_module == NULL", __func__);
return;
}
module_put(uvd->handle->md_module);
@@ -675,13 +675,13 @@ int usbvideo_register(
/* Check parameters for sanity */
if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
- err("%s: Illegal call", __FUNCTION__);
+ err("%s: Illegal call", __func__);
return -EINVAL;
}
/* Check registration callback - must be set! */
if (cbTbl->probe == NULL) {
- err("%s: probe() is required!", __FUNCTION__);
+ err("%s: probe() is required!", __func__);
return -EINVAL;
}
@@ -692,7 +692,7 @@ int usbvideo_register(
return -ENOMEM;
}
dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
- __FUNCTION__, cams, base_size, num_cams);
+ __func__, cams, base_size, num_cams);
/* Copy callbacks, apply defaults for those that are not set */
memmove(&cams->cb, cbTbl, sizeof(cams->cb));
@@ -721,7 +721,7 @@ int usbvideo_register(
up->user_data = kmalloc(up->user_size, GFP_KERNEL);
if (up->user_data == NULL) {
err("%s: Failed to allocate user_data (%d. bytes)",
- __FUNCTION__, up->user_size);
+ __func__, up->user_size);
while (i) {
up = &cams->cam[--i];
kfree(up->user_data);
@@ -730,7 +730,7 @@ int usbvideo_register(
return -ENOMEM;
}
dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
- __FUNCTION__, i, up->user_data, up->user_size);
+ __func__, i, up->user_data, up->user_size);
}
}
@@ -776,19 +776,19 @@ void usbvideo_Deregister(struct usbvideo **pCams)
int i;
if (pCams == NULL) {
- err("%s: pCams == NULL", __FUNCTION__);
+ err("%s: pCams == NULL", __func__);
return;
}
cams = *pCams;
if (cams == NULL) {
- err("%s: cams == NULL", __FUNCTION__);
+ err("%s: cams == NULL", __func__);
return;
}
- dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
+ dbg("%s: Deregistering %s driver.", __func__, cams->drvName);
usb_deregister(&cams->usbdrv);
- dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
+ dbg("%s: Deallocating cams=$%p (%d. cameras)", __func__, cams, cams->num_cameras);
for (i=0; i < cams->num_cameras; i++) {
struct uvd *up = &cams->cam[i];
int warning = 0;
@@ -802,16 +802,16 @@ void usbvideo_Deregister(struct usbvideo **pCams)
}
if (warning) {
err("%s: Warning: user_data=$%p user_size=%d.",
- __FUNCTION__, up->user_data, up->user_size);
+ __func__, up->user_data, up->user_size);
} else {
dbg("%s: Freeing %d. $%p->user_data=$%p",
- __FUNCTION__, i, up, up->user_data);
+ __func__, i, up, up->user_data);
kfree(up->user_data);
}
}
/* Whole array was allocated in one chunk */
dbg("%s: Freed %d uvd structures",
- __FUNCTION__, cams->num_cameras);
+ __func__, cams->num_cameras);
kfree(cams);
*pCams = NULL;
}
@@ -846,7 +846,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
int i;
if (uvd == NULL) {
- err("%s($%p): Illegal call.", __FUNCTION__, intf);
+ err("%s($%p): Illegal call.", __func__, intf);
return;
}
@@ -854,7 +854,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
usbvideo_ClientIncModCount(uvd);
if (uvd->debug > 0)
- info("%s(%p.)", __FUNCTION__, intf);
+ info("%s(%p.)", __func__, intf);
mutex_lock(&uvd->lock);
uvd->remove_pending = 1; /* Now all ISO data will be ignored */
@@ -870,10 +870,10 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
video_unregister_device(&uvd->vdev);
if (uvd->debug > 0)
- info("%s: Video unregistered.", __FUNCTION__);
+ info("%s: Video unregistered.", __func__);
if (uvd->user)
- info("%s: In use, disconnect pending.", __FUNCTION__);
+ info("%s: In use, disconnect pending.", __func__);
else
usbvideo_CameraRelease(uvd);
mutex_unlock(&uvd->lock);
@@ -895,7 +895,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
static void usbvideo_CameraRelease(struct uvd *uvd)
{
if (uvd == NULL) {
- err("%s: Illegal call", __FUNCTION__);
+ err("%s: Illegal call", __func__);
return;
}
@@ -1013,18 +1013,18 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
char tmp1[20], tmp2[20]; /* Buffers for printing */
if (uvd == NULL) {
- err("%s: Illegal call.", __FUNCTION__);
+ err("%s: Illegal call.", __func__);
return -EINVAL;
}
if (uvd->video_endp == 0) {
- info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
+ info("%s: No video endpoint specified; data pump disabled.", __func__);
}
if (uvd->paletteBits == 0) {
- err("%s: No palettes specified!", __FUNCTION__);
+ err("%s: No palettes specified!", __func__);
return -EINVAL;
}
if (uvd->defaultPalette == 0) {
- info("%s: No default palette!", __FUNCTION__);
+ info("%s: No default palette!", __func__);
}
uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
@@ -1034,7 +1034,7 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
if (uvd->debug > 0) {
info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
- __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
+ __func__, uvd->iface, uvd->video_endp, uvd->paletteBits);
}
if (uvd->dev == NULL) {
err("%s: uvd->dev == NULL", __func__);
@@ -1042,11 +1042,11 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
}
uvd->vdev.dev = &uvd->dev->dev;
if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
- err("%s: video_register_device failed", __FUNCTION__);
+ err("%s: video_register_device failed", __func__);
return -EPIPE;
}
if (uvd->debug > 1) {
- info("%s: video_register_device() successful", __FUNCTION__);
+ info("%s: video_register_device() successful", __func__);
}
info("%s on /dev/video%d: canvas=%s videosize=%s",
@@ -1113,14 +1113,14 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
int i, errCode = 0;
if (uvd->debug > 1)
- info("%s($%p)", __FUNCTION__, dev);
+ info("%s($%p)", __func__, dev);
if (0 < usbvideo_ClientIncModCount(uvd))
return -ENODEV;
mutex_lock(&uvd->lock);
if (uvd->user) {
- err("%s: Someone tried to open an already opened device!", __FUNCTION__);
+ err("%s: Someone tried to open an already opened device!", __func__);
errCode = -EBUSY;
} else {
/* Clear statistics */
@@ -1136,7 +1136,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
if ((uvd->fbuf == NULL) ||
(!RingQueue_IsAllocated(&uvd->dp))) {
- err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
+ err("%s: Failed to allocate fbuf or dp", __func__);
errCode = -ENOMEM;
} else {
/* Allocate all buffers */
@@ -1180,19 +1180,19 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
if (errCode == 0) {
if (VALID_CALLBACK(uvd, setupOnOpen)) {
if (uvd->debug > 1)
- info("%s: setupOnOpen callback", __FUNCTION__);
+ info("%s: setupOnOpen callback", __func__);
errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
if (errCode < 0) {
err("%s: setupOnOpen callback failed (%d.).",
- __FUNCTION__, errCode);
+ __func__, errCode);
} else if (uvd->debug > 1) {
- info("%s: setupOnOpen callback successful", __FUNCTION__);
+ info("%s: setupOnOpen callback successful", __func__);
}
}
if (errCode == 0) {
uvd->settingsAdjusted = 0;
if (uvd->debug > 1)
- info("%s: Open succeeded.", __FUNCTION__);
+ info("%s: Open succeeded.", __func__);
uvd->user++;
file->private_data = uvd;
}
@@ -1202,7 +1202,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
if (errCode != 0)
usbvideo_ClientDecModCount(uvd);
if (uvd->debug > 0)
- info("%s: Returning %d.", __FUNCTION__, errCode);
+ info("%s: Returning %d.", __func__, errCode);
return errCode;
}
@@ -1225,7 +1225,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
int i;
if (uvd->debug > 1)
- info("%s($%p)", __FUNCTION__, dev);
+ info("%s($%p)", __func__, dev);
mutex_lock(&uvd->lock);
GET_CALLBACK(uvd, stopDataPump)(uvd);
@@ -1252,7 +1252,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
usbvideo_ClientDecModCount(uvd);
if (uvd->debug > 1)
- info("%s: Completed.", __FUNCTION__);
+ info("%s: Completed.", __func__);
file->private_data = NULL;
return 0;
}
@@ -1506,7 +1506,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
return -EFAULT;
if (uvd->debug >= 1)
- info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
+ info("%s: %Zd. bytes, noblock=%d.", __func__, count, noblock);
mutex_lock(&uvd->lock);
@@ -1553,7 +1553,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
*/
if (frmx == -1) {
if (uvd->defaultPalette == 0) {
- err("%s: No default palette; don't know what to do!", __FUNCTION__);
+ err("%s: No default palette; don't know what to do!", __func__);
count = -EFAULT;
goto read_done;
}
@@ -1625,7 +1625,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
frame->seqRead_Index += count;
if (uvd->debug >= 1) {
err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
- __FUNCTION__, count, frame->seqRead_Index);
+ __func__, count, frame->seqRead_Index);
}
/* Finally check if the frame is done with and "release" it */
@@ -1636,7 +1636,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
/* Mark it as available to be used again. */
uvd->frame[frmx].frameState = FrameState_Unused;
if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
- err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
+ err("%s: usbvideo_NewFrame failed.", __func__);
}
}
read_done:
@@ -1747,10 +1747,10 @@ static int usbvideo_StartDataPump(struct uvd *uvd)
int i, errFlag;
if (uvd->debug > 1)
- info("%s($%p)", __FUNCTION__, uvd);
+ info("%s($%p)", __func__, uvd);
if (!CAMERA_IS_OPERATIONAL(uvd)) {
- err("%s: Camera is not operational", __FUNCTION__);
+ err("%s: Camera is not operational", __func__);
return -EFAULT;
}
uvd->curframe = -1;
@@ -1758,14 +1758,14 @@ static int usbvideo_StartDataPump(struct uvd *uvd)
/* Alternate interface 1 is is the biggest frame size */
i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
if (i < 0) {
- err("%s: usb_set_interface error", __FUNCTION__);
+ err("%s: usb_set_interface error", __func__);
uvd->last_error = i;
return -EBUSY;
}
if (VALID_CALLBACK(uvd, videoStart))
GET_CALLBACK(uvd, videoStart)(uvd);
else
- err("%s: videoStart not set", __FUNCTION__);
+ err("%s: videoStart not set", __func__);
/* We double buffer the Iso lists */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
@@ -1790,12 +1790,12 @@ static int usbvideo_StartDataPump(struct uvd *uvd)
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
if (errFlag)
- err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
+ err("%s: usb_submit_isoc(%d) ret %d", __func__, i, errFlag);
}
uvd->streaming = 1;
if (uvd->debug > 1)
- info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
+ info("%s: streaming=1 video_endp=$%02x", __func__, uvd->video_endp);
return 0;
}
@@ -1817,14 +1817,14 @@ static void usbvideo_StopDataPump(struct uvd *uvd)
return;
if (uvd->debug > 1)
- info("%s($%p)", __FUNCTION__, uvd);
+ info("%s($%p)", __func__, uvd);
/* Unschedule all of the iso td's */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
usb_kill_urb(uvd->sbuf[i].urb);
}
if (uvd->debug > 1)
- info("%s: streaming=0", __FUNCTION__);
+ info("%s: streaming=0", __func__);
uvd->streaming = 0;
if (!uvd->remove_pending) {
@@ -1832,12 +1832,12 @@ static void usbvideo_StopDataPump(struct uvd *uvd)
if (VALID_CALLBACK(uvd, videoStop))
GET_CALLBACK(uvd, videoStop)(uvd);
else
- err("%s: videoStop not set", __FUNCTION__);
+ err("%s: videoStop not set", __func__);
/* Set packet size to 0 */
j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
if (j < 0) {
- err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
+ err("%s: usb_set_interface() error %d.", __func__, j);
uvd->last_error = j;
}
}
@@ -1961,12 +1961,12 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
struct usbvideo_frame *frame = &uvd->frame[frameNum];
if (uvd->debug >= 2)
- info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
+ info("%s($%p,%d.)", __func__, uvd, frameNum);
switch (frame->frameState) {
case FrameState_Unused:
if (uvd->debug >= 2)
- info("%s: FrameState_Unused", __FUNCTION__);
+ info("%s: FrameState_Unused", __func__);
return -EINVAL;
case FrameState_Ready:
case FrameState_Grabbing:
@@ -1976,7 +1976,7 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
redo:
if (!CAMERA_IS_OPERATIONAL(uvd)) {
if (uvd->debug >= 2)
- info("%s: Camera is not operational (1)", __FUNCTION__);
+ info("%s: Camera is not operational (1)", __func__);
return -EIO;
}
ntries = 0;
@@ -1985,24 +1985,24 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
signalPending = signal_pending(current);
if (!CAMERA_IS_OPERATIONAL(uvd)) {
if (uvd->debug >= 2)
- info("%s: Camera is not operational (2)", __FUNCTION__);
+ info("%s: Camera is not operational (2)", __func__);
return -EIO;
}
assert(uvd->fbuf != NULL);
if (signalPending) {
if (uvd->debug >= 2)
- info("%s: Signal=$%08x", __FUNCTION__, signalPending);
+ info("%s: Signal=$%08x", __func__, signalPending);
if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
usbvideo_TestPattern(uvd, 1, 0);
uvd->curframe = -1;
uvd->stats.frame_num++;
if (uvd->debug >= 2)
- info("%s: Forced test pattern screen", __FUNCTION__);
+ info("%s: Forced test pattern screen", __func__);
return 0;
} else {
/* Standard answer: Interrupted! */
if (uvd->debug >= 2)
- info("%s: Interrupted!", __FUNCTION__);
+ info("%s: Interrupted!", __func__);
return -EINTR;
}
} else {
@@ -2012,17 +2012,17 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
else if (VALID_CALLBACK(uvd, processData))
GET_CALLBACK(uvd, processData)(uvd, frame);
else
- err("%s: processData not set", __FUNCTION__);
+ err("%s: processData not set", __func__);
}
} while (frame->frameState == FrameState_Grabbing);
if (uvd->debug >= 2) {
info("%s: Grabbing done; state=%d. (%lu. bytes)",
- __FUNCTION__, frame->frameState, frame->seqRead_Length);
+ __func__, frame->frameState, frame->seqRead_Length);
}
if (frame->frameState == FrameState_Error) {
int ret = usbvideo_NewFrame(uvd, frameNum);
if (ret < 0) {
- err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
+ err("%s: usbvideo_NewFrame() failed (%d.)", __func__, ret);
return ret;
}
goto redo;
@@ -2054,7 +2054,7 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
}
frame->frameState = FrameState_Done_Hold;
if (uvd->debug >= 2)
- info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
+ info("%s: Entered FrameState_Done_Hold state.", __func__);
return 0;
case FrameState_Done_Hold:
@@ -2065,12 +2065,12 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
* it will be released back into the wild to roam freely.
*/
if (uvd->debug >= 2)
- info("%s: FrameState_Done_Hold state.", __FUNCTION__);
+ info("%s: FrameState_Done_Hold state.", __func__);
return 0;
}
/* Catch-all for other cases. We shall not be here. */
- err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
+ err("%s: Invalid state %d.", __func__, frame->frameState);
frame->frameState = FrameState_Unused;
return 0;
}
@@ -2166,7 +2166,7 @@ static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
const int ccm = 128; /* Color correction median - see below */
if ((uvd == NULL) || (frame == NULL)) {
- err("%s: Illegal call.", __FUNCTION__);
+ err("%s: Illegal call.", __func__);
return;
}
adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
diff --git a/linux/drivers/media/video/usbvideo/vicam.c b/linux/drivers/media/video/usbvideo/vicam.c
index 984f4b756..049f588ae 100644
--- a/linux/drivers/media/video/usbvideo/vicam.c
+++ b/linux/drivers/media/video/usbvideo/vicam.c
@@ -50,7 +50,7 @@
// #define VICAM_DEBUG
#ifdef VICAM_DEBUG
-#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __func__, lineno, ##args)
#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
#else
#define DBG(fmn,args...) do {} while(0)
@@ -72,12 +72,6 @@
#define VICAM_HEADER_SIZE 64
-#define clamp( x, l, h ) max_t( __typeof__( x ), \
- ( l ), \
- min_t( __typeof__( x ), \
- ( h ), \
- ( x ) ) )
-
/* Not sure what all the bytes in these char
* arrays do, but they're necessary to make
* the camera work.
diff --git a/linux/drivers/media/video/usbvision/Makefile b/linux/drivers/media/video/usbvision/Makefile
index 9ac92a80c..338718750 100644
--- a/linux/drivers/media/video/usbvision/Makefile
+++ b/linux/drivers/media/video/usbvision/Makefile
@@ -3,3 +3,4 @@ usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-
obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c
index 96155fd92..55b3f5e60 100644
--- a/linux/drivers/media/video/usbvision/usbvision-video.c
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c
@@ -1031,7 +1031,7 @@ static int vidioc_streamoff(struct file *file,
return 0;
}
-static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
struct v4l2_fmtdesc *vfd)
{
if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
@@ -1045,7 +1045,7 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_fmt_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
struct v4l2_format *vf)
{
struct video_device *dev = video_devdata(file);
@@ -1063,7 +1063,7 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_try_fmt_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
struct v4l2_format *vf)
{
struct video_device *dev = video_devdata(file);
@@ -1093,7 +1093,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *vf)
{
struct video_device *dev = video_devdata(file);
@@ -1101,7 +1101,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
(struct usb_usbvision *) video_get_drvdata(dev);
int ret;
- if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) {
+ if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) {
return ret;
}
@@ -1501,10 +1501,10 @@ static struct video_device usbvision_video_template = {
#endif
.minor = -1,
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
- .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
- .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index 34079657e..b721aca4e 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -711,13 +711,14 @@ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
/* Helper function for I2C legacy drivers */
int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
- const char *name, int (*probe)(struct i2c_client *))
+ const char *name,
+ int (*probe)(struct i2c_client *, const struct i2c_device_id *))
{
struct i2c_client *client;
int err;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
@@ -728,7 +729,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver
#endif
strlcpy(client->name, name, sizeof(client->name));
- err = probe(client);
+ err = probe(client, NULL);
if (err == 0) {
i2c_attach_client(client);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
diff --git a/linux/drivers/media/video/videobuf-core.c b/linux/drivers/media/video/videobuf-core.c
index 5220023c2..16c32c68c 100644
--- a/linux/drivers/media/video/videobuf-core.c
+++ b/linux/drivers/media/video/videobuf-core.c
@@ -95,13 +95,17 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
return CALL(q, iolock, q, vb, fbuf);
}
-/* --------------------------------------------------------------------- */
-
-static int videobuf_mmap_setup_default(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+void *videobuf_queue_to_vmalloc (struct videobuf_queue *q,
+ struct videobuf_buffer *buf)
{
- return 0;
+ if (q->int_ops->vmalloc)
+ return q->int_ops->vmalloc(buf);
+ else
+ return NULL;
}
+EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
+
+/* --------------------------------------------------------------------- */
void videobuf_queue_core_init(struct videobuf_queue *q,
@@ -124,15 +128,15 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
q->priv_data = priv;
q->int_ops = int_ops;
- if (!q->int_ops->mmap_setup)
- q->int_ops->mmap_setup = videobuf_mmap_setup_default;
-
/* All buffer operations are mandatory */
BUG_ON(!q->ops->buf_setup);
BUG_ON(!q->ops->buf_prepare);
BUG_ON(!q->ops->buf_queue);
BUG_ON(!q->ops->buf_release);
+ /* Lock is mandatory for queue_cancel to work */
+ BUG_ON(!irqlock);
+
/* Having implementations for abstract methods are mandatory */
BUG_ON(!q->int_ops);
@@ -190,8 +194,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q)
wake_up_interruptible_sync(&q->wait);
/* remove queued buffers from list */
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -201,8 +204,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q)
wake_up_all(&q->bufs[i]->done);
}
}
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
/* free all buffers + clear queue */
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
@@ -304,6 +306,8 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
rc = CALL(q, mmap_free, q);
+ q->is_mmapped = 0;
+
if (rc < 0)
return rc;
@@ -328,7 +332,7 @@ int videobuf_mmap_free(struct videobuf_queue *q)
}
/* Locking: Caller holds q->vb_lock */
-static int __videobuf_mmap_setup(struct videobuf_queue *q,
+int __videobuf_mmap_setup(struct videobuf_queue *q,
unsigned int bcount, unsigned int bsize,
enum v4l2_memory memory)
{
@@ -355,9 +359,6 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
switch (memory) {
case V4L2_MEMORY_MMAP:
q->bufs[i]->boff = bsize * i;
- err = q->int_ops->mmap_setup(q, q->bufs[i]);
- if (err)
- break;
break;
case V4L2_MEMORY_USERPTR:
case V4L2_MEMORY_OVERLAY:
@@ -559,11 +560,9 @@ int videobuf_qbuf(struct videobuf_queue *q,
list_add_tail(&buf->stream, &q->stream);
if (q->streaming) {
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
}
dprintk(1, "qbuf: succeded\n");
retval = 0;
@@ -700,13 +699,11 @@ int videobuf_streamon(struct videobuf_queue *q)
if (q->streaming)
goto done;
q->streaming = 1;
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
list_for_each_entry(buf, &q->stream, stream)
if (buf->state == VIDEOBUF_PREPARED)
q->ops->buf_queue(q, buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
wake_up_interruptible_sync(&q->wait);
done:
@@ -762,11 +759,9 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
goto done;
/* start capture & wait */
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, q->read_buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
retval = videobuf_waiton(q->read_buf, 0, 0);
if (0 == retval) {
CALL(q, sync, q, q->read_buf);
@@ -827,12 +822,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
q->read_buf = NULL;
goto done;
}
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, q->read_buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
+
q->read_off = 0;
}
@@ -898,12 +892,10 @@ static int __videobuf_read_start(struct videobuf_queue *q)
return err;
list_add_tail(&q->bufs[i]->stream, &q->stream);
}
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
for (i = 0; i < count; i++)
q->ops->buf_queue(q, q->bufs[i]);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
q->reading = 1;
return 0;
}
@@ -912,7 +904,6 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
{
int i;
-
videobuf_queue_cancel(q);
__videobuf_mmap_free(q);
INIT_LIST_HEAD(&q->stream);
@@ -967,7 +958,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- dprintk(2, "%s\n", __FUNCTION__);
+ dprintk(2, "%s\n", __func__);
mutex_lock(&q->vb_lock);
retval = -EBUSY;
if (q->streaming)
@@ -1016,11 +1007,9 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
if (q->read_off == q->read_buf->size) {
list_add_tail(&q->read_buf->stream,
&q->stream);
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, q->read_buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
q->read_buf = NULL;
}
if (retval < 0)
@@ -1080,6 +1069,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
mutex_lock(&q->vb_lock);
retval = CALL(q, mmap_mapper, q, vma);
+ q->is_mmapped = 1;
mutex_unlock(&q->vb_lock);
return retval;
@@ -1140,6 +1130,7 @@ EXPORT_SYMBOL_GPL(videobuf_read_stream);
EXPORT_SYMBOL_GPL(videobuf_read_one);
EXPORT_SYMBOL_GPL(videobuf_poll_stream);
+EXPORT_SYMBOL_GPL(__videobuf_mmap_setup);
EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
EXPORT_SYMBOL_GPL(videobuf_mmap_free);
EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
diff --git a/linux/drivers/media/video/videobuf-dma-sg.c b/linux/drivers/media/video/videobuf-dma-sg.c
index 06a219e0d..7d459ed6b 100644
--- a/linux/drivers/media/video/videobuf-dma-sg.c
+++ b/linux/drivers/media/video/videobuf-dma-sg.c
@@ -163,9 +163,6 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
data,size,dma->nr_pages);
- dma->varea = (void *) data;
-
-
err = get_user_pages(current,current->mm,
data & PAGE_MASK, dma->nr_pages,
rw == READ, 1, /* force */
@@ -253,7 +250,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
dma->nr_pages, dma->direction);
if (0 == dma->sglen) {
printk(KERN_WARNING
- "%s: videobuf_map_sg failed\n",__FUNCTION__);
+ "%s: videobuf_map_sg failed\n",__func__);
kfree(dma->sglist);
dma->sglist = NULL;
dma->sglen = 0;
@@ -305,7 +302,6 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
vfree(dma->vmalloc);
dma->vmalloc = NULL;
- dma->varea = NULL;
if (dma->bus_addr) {
dma->bus_addr = 0;
@@ -476,12 +472,22 @@ static void *__videobuf_alloc(size_t size)
videobuf_dma_init(&mem->dma);
dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
- __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+ __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
mem,(long)sizeof(*mem));
return vb;
}
+static void *__videobuf_to_vmalloc (struct videobuf_buffer *buf)
+{
+ struct videobuf_dma_sg_memory *mem = buf->priv;
+ BUG_ON(!mem);
+
+ MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
+
+ return mem->dma.vmalloc;
+}
+
static int __videobuf_iolock (struct videobuf_queue* q,
struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf)
@@ -727,6 +733,7 @@ static struct videobuf_qtype_ops sg_ops = {
.mmap_mapper = __videobuf_mmap_mapper,
.video_copy_to_user = __videobuf_copy_to_user,
.copy_stream = __videobuf_copy_stream,
+ .vmalloc = __videobuf_to_vmalloc,
};
void *videobuf_sg_alloc(size_t size)
diff --git a/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c
index 8966a53db..9a821371a 100644
--- a/linux/drivers/media/video/videobuf-dvb.c
+++ b/linux/drivers/media/video/videobuf-dvb.c
@@ -21,13 +21,14 @@
#include <linux/fs.h>
#include <linux/kthread.h>
#include <linux/file.h>
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
#include <linux/suspend.h>
#else
#include <linux/freezer.h>
#endif
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-core.h>
#include <media/videobuf-dvb.h>
#include "compat.h"
@@ -51,7 +52,7 @@ static int videobuf_dvb_thread(void *data)
struct videobuf_buffer *buf;
unsigned long flags;
int err;
- struct videobuf_dmabuf *dma;
+ void *outp;
dprintk("dvb thread started\n");
set_freezable();
@@ -72,9 +73,10 @@ static int videobuf_dvb_thread(void *data)
try_to_freeze();
/* feed buffer data to demux */
- dma=videobuf_to_dma(buf);
+ outp = videobuf_queue_to_vmalloc (&dvb->dvbq, buf);
+
if (buf->state == VIDEOBUF_DONE)
- dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
+ dvb_dmx_swfilter(&dvb->demux, outp,
buf->size);
/* requeue buffer */
@@ -144,14 +146,16 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
int videobuf_dvb_register(struct videobuf_dvb *dvb,
struct module *module,
void *adapter_priv,
- struct device *device)
+ struct device *device,
+ short *adapter_nr)
{
int result;
mutex_init(&dvb->lock);
/* register adapter */
- result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device);
+ result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device,
+ adapter_nr);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
dvb->name, result);
diff --git a/linux/drivers/media/video/videobuf-vmalloc.c b/linux/drivers/media/video/videobuf-vmalloc.c
index 3bc7308af..6f487b348 100644
--- a/linux/drivers/media/video/videobuf-vmalloc.c
+++ b/linux/drivers/media/video/videobuf-vmalloc.c
@@ -58,20 +58,26 @@ videobuf_vm_open(struct vm_area_struct *vma)
map->count++;
}
-static void
-videobuf_vm_close(struct vm_area_struct *vma)
+static void videobuf_vm_close(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
struct videobuf_queue *q = map->q;
int i;
- dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n",map,
- map->count,vma->vm_start,vma->vm_end);
+ dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
+ map->count, vma->vm_start, vma->vm_end);
map->count--;
if (0 == map->count) {
- dprintk(1,"munmap %p q=%p\n",map,q);
+ struct videobuf_vmalloc_memory *mem;
+
+ dprintk(1, "munmap %p q=%p\n", map, q);
mutex_lock(&q->vb_lock);
+
+ /* We need first to cancel streams, before unmapping */
+ if (q->streaming)
+ videobuf_queue_cancel(q);
+
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -79,12 +85,35 @@ videobuf_vm_close(struct vm_area_struct *vma)
if (q->bufs[i]->map != map)
continue;
+ mem = q->bufs[i]->priv;
+ if (mem) {
+ /* This callback is called only if kernel has
+ allocated memory and this memory is mmapped.
+ In this case, memory should be freed,
+ in order to do memory unmap.
+ */
+
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
+
+ /* vfree is not atomic - can't be
+ called with IRQ's disabled
+ */
+ dprintk(1, "%s: buf[%d] freeing (%p)\n",
+ __func__, i, mem->vmalloc);
+
+ vfree(mem->vmalloc);
+ mem->vmalloc = NULL;
+ }
+
q->bufs[i]->map = NULL;
q->bufs[i]->baddr = 0;
}
- mutex_unlock(&q->vb_lock);
+
kfree(map);
+
+ mutex_unlock(&q->vb_lock);
}
+
return;
}
@@ -115,7 +144,7 @@ static void *__videobuf_alloc(size_t size)
mem->magic=MAGIC_VMAL_MEM;
dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
- __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+ __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
mem,(long)sizeof(*mem));
return vb;
@@ -125,53 +154,77 @@ static int __videobuf_iolock (struct videobuf_queue* q,
struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf)
{
+ struct videobuf_vmalloc_memory *mem = vb->priv;
int pages;
- struct videobuf_vmalloc_memory *mem=vb->priv;
BUG_ON(!mem);
- MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
- pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+ switch (vb->memory) {
+ case V4L2_MEMORY_MMAP:
+ dprintk(1, "%s memory method MMAP\n", __func__);
- /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
- if ((vb->memory != V4L2_MEMORY_MMAP) &&
- (vb->memory != V4L2_MEMORY_USERPTR) ) {
- printk(KERN_ERR "Method currently unsupported.\n");
- return -EINVAL;
- }
+ /* All handling should be done by __videobuf_mmap_mapper() */
+ if (!mem->vmalloc) {
+ printk(KERN_ERR "memory is not alloced/mmapped.\n");
+ return -EINVAL;
+ }
+ break;
+ case V4L2_MEMORY_USERPTR:
+ pages = PAGE_ALIGN(vb->size);
- /* FIXME: should be tested with kernel mmap mem */
- mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size));
- if (NULL == mem->vmalloc) {
- printk(KERN_ERR "vmalloc (%d pages) failed\n",pages);
- return -ENOMEM;
- }
+ dprintk(1, "%s memory method USERPTR\n", __func__);
- dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)mem->vmalloc,
- pages << PAGE_SHIFT);
+#if 1 /* keep */
+ if (vb->baddr) {
+ printk(KERN_ERR "USERPTR is currently not supported\n");
+ return -EINVAL;
+ }
+#endif
- return 0;
-}
+ /* The only USERPTR currently supported is the one needed for
+ read() method.
+ */
-static int __videobuf_mmap_setup(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- int retval = 0;
- BUG_ON(vb->memory != V4L2_MEMORY_MMAP);
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- /* bsize == size since the buffer needs to be large enough to
- * hold an entire frame, not the case in the read case for
- * example*/
- vb->size = vb->bsize;
- retval = __videobuf_iolock(q, vb, NULL);
- if (!retval) {
- /* Don't IOLOCK later */
- vb->state = VIDEOBUF_IDLE;
+ mem->vmalloc = vmalloc_user(pages);
+ if (!mem->vmalloc) {
+ printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
+ return -ENOMEM;
+ }
+ dprintk(1, "vmalloc is at addr %p (%d pages)\n",
+ mem->vmalloc, pages);
+
+#if 0 /* keep */
+ int rc;
+ /* Kernel userptr is used also by read() method. In this case,
+ there's no need to remap, since data will be copied to user
+ */
+ if (!vb->baddr)
+ return 0;
+
+ /* FIXME: to properly support USERPTR, remap should occur.
+ The code bellow won't work, since mem->vma = NULL
+ */
+ /* Try to remap memory */
+ rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
+ if (rc < 0) {
+ printk(KERN_ERR "mmap: remap failed with error %d. ", rc);
+ return -ENOMEM;
}
+#endif
+
+ break;
+ case V4L2_MEMORY_OVERLAY:
+ default:
+ dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
+
+ /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
+ printk(KERN_ERR "Memory method currently unsupported.\n");
+ return -EINVAL;
}
- return retval;
+
+ return 0;
}
static int __videobuf_sync(struct videobuf_queue *q,
@@ -184,6 +237,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
{
unsigned int i;
+ dprintk(1, "%s\n", __func__);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (q->bufs[i]) {
if (q->bufs[i]->map)
@@ -200,10 +254,11 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct videobuf_vmalloc_memory *mem;
struct videobuf_mapping *map;
unsigned int first;
- int retval;
+ int retval, pages;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+ dprintk(1, "%s\n", __func__);
+ if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
return -EINVAL;
/* look for first buffer to map */
@@ -223,39 +278,55 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
}
/* create mapping + update buffer list */
- map = q->bufs[first]->map = kzalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+ map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
if (NULL == map)
return -ENOMEM;
+ q->bufs[first]->map = map;
map->start = vma->vm_start;
map->end = vma->vm_end;
map->q = q;
q->bufs[first]->baddr = vma->vm_start;
- vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
- vma->vm_private_data = map;
+ mem = q->bufs[first]->priv;
+ BUG_ON(!mem);
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
- mem=q->bufs[first]->priv;
- BUG_ON (!mem);
- MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+ pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
+ mem->vmalloc = vmalloc_user(pages);
+ if (!mem->vmalloc) {
+ printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
+ goto error;
+ }
+ dprintk(1, "vmalloc is at addr %p (%d pages)\n",
+ mem->vmalloc, pages);
/* Try to remap memory */
- retval=remap_vmalloc_range(vma, mem->vmalloc,0);
- if (retval<0) {
- dprintk(1, "mmap: failed to remap_vmalloc_range\n");
- return -EINVAL;
+ retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
+ if (retval < 0) {
+ printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
+ vfree(mem->vmalloc);
+ goto error;
}
+ vma->vm_ops = &videobuf_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_private_data = map;
+
dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
- map,q,vma->vm_start,vma->vm_end,
+ map, q, vma->vm_start, vma->vm_end,
(long int) q->bufs[first]->bsize,
- vma->vm_pgoff,first);
+ vma->vm_pgoff, first);
videobuf_vm_open(vma);
- return (0);
+ return 0;
+
+error:
+ mem = NULL;
+ kfree(map);
+ return -ENOMEM;
}
static int __videobuf_copy_to_user ( struct videobuf_queue *q,
@@ -313,11 +384,11 @@ static struct videobuf_qtype_ops qops = {
.alloc = __videobuf_alloc,
.iolock = __videobuf_iolock,
.sync = __videobuf_sync,
- .mmap_setup = __videobuf_mmap_setup,
.mmap_free = __videobuf_mmap_free,
.mmap_mapper = __videobuf_mmap_mapper,
.video_copy_to_user = __videobuf_copy_to_user,
.copy_stream = __videobuf_copy_stream,
+ .vmalloc = videobuf_to_vmalloc,
};
void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
@@ -347,13 +418,24 @@ EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
void videobuf_vmalloc_free (struct videobuf_buffer *buf)
{
- struct videobuf_vmalloc_memory *mem=buf->priv;
- BUG_ON (!mem);
+ struct videobuf_vmalloc_memory *mem = buf->priv;
- MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+ /* mmapped memory can't be freed here, otherwise mmapped region
+ would be released, while still needed. In this case, the memory
+ release should happen inside videobuf_vm_close().
+ So, it should free memory only if the memory were allocated for
+ read() operation.
+ */
+ if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0))
+ return;
+
+ if (!mem)
+ return;
+
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
vfree(mem->vmalloc);
- mem->vmalloc=NULL;
+ mem->vmalloc = NULL;
return;
}
diff --git a/linux/drivers/media/video/videocodec.c b/linux/drivers/media/video/videocodec.c
index b30b6b2a9..cf24956f3 100644
--- a/linux/drivers/media/video/videocodec.c
+++ b/linux/drivers/media/video/videocodec.c
@@ -39,6 +39,7 @@
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
#endif
@@ -320,56 +321,22 @@ videocodec_unregister (const struct videocodec *codec)
}
#ifdef CONFIG_PROC_FS
-/* ============ */
-/* procfs stuff */
-/* ============ */
-
-static char *videocodec_buf = NULL;
-static int videocodec_bufsize;
-
-static int
-videocodec_build_table (void)
+static int proc_videocodecs_show(struct seq_file *m, void *v)
{
struct codec_list *h = codeclist_top;
struct attached_list *a;
- int i = 0, size;
-
- // sum up amount of slaves plus their attached masters
- while (h) {
- i += h->attached + 1;
- h = h->next;
- }
-#define LINESIZE 100
- size = LINESIZE * (i + 1);
- dprintk(3, "videocodec_build table: %d entries, %d bytes\n", i,
- size);
-
- kfree(videocodec_buf);
- videocodec_buf = kmalloc(size, GFP_KERNEL);
-
- if (!videocodec_buf)
- return 0;
-
- i = 0;
- i += scnprintf(videocodec_buf + i, size - 1,
- "<S>lave or attached <M>aster name type flags magic ");
- i += scnprintf(videocodec_buf + i, size -i - 1, "(connected as)\n");
+ seq_printf(m, "<S>lave or attached <M>aster name type flags magic ");
+ seq_printf(m, "(connected as)\n");
h = codeclist_top;
while (h) {
- if (i > (size - LINESIZE))
- break; // security check
- i += scnprintf(videocodec_buf + i, size -i -1,
- "S %32s %04x %08lx %08lx (TEMPLATE)\n",
+ seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",
h->codec->name, h->codec->type,
h->codec->flags, h->codec->magic);
a = h->list;
while (a) {
- if (i > (size - LINESIZE))
- break; // security check
- i += scnprintf(videocodec_buf + i, size -i -1,
- "M %32s %04x %08lx %08lx (%s)\n",
+ seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n",
a->codec->master_data->name,
a->codec->master_data->type,
a->codec->master_data->flags,
@@ -380,54 +347,21 @@ videocodec_build_table (void)
h = h->next;
}
- return i;
+ return 0;
}
-//The definition:
-//typedef int (read_proc_t)(char *page, char **start, off_t off,
-// int count, int *eof, void *data);
-
-static int
-videocodec_info (char *buffer,
- char **buffer_location,
- off_t offset,
- int buffer_length,
- int *eof,
- void *data)
+static int proc_videocodecs_open(struct inode *inode, struct file *file)
{
- int size;
-
- dprintk(3, "videocodec_info: offset: %ld, len %d / size %d\n",
- offset, buffer_length, videocodec_bufsize);
-
- if (offset == 0) {
- videocodec_bufsize = videocodec_build_table();
- }
- if ((offset < 0) || (offset >= videocodec_bufsize)) {
- dprintk(4,
- "videocodec_info: call delivers no result, return 0\n");
- *eof = 1;
- return 0;
- }
-
- if (buffer_length < (videocodec_bufsize - offset)) {
- dprintk(4, "videocodec_info: %ld needed, %d got\n",
- videocodec_bufsize - offset, buffer_length);
- size = buffer_length;
- } else {
- dprintk(4, "videocodec_info: last reading of %ld bytes\n",
- videocodec_bufsize - offset);
- size = videocodec_bufsize - offset;
- *eof = 1;
- }
-
- memcpy(buffer, videocodec_buf + offset, size);
- /* doesn't work... */
- /* copy_to_user(buffer, videocodec_buf+offset, size); */
- /* *buffer_location = videocodec_buf+offset; */
-
- return size;
+ return single_open(file, proc_videocodecs_show, NULL);
}
+
+static const struct file_operations videocodecs_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_videocodecs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
/* ===================== */
@@ -444,16 +378,8 @@ videocodec_init (void)
VIDEOCODEC_VERSION);
#ifdef CONFIG_PROC_FS
- videocodec_buf = NULL;
- videocodec_bufsize = 0;
-
- videocodec_proc_entry = create_proc_entry("videocodecs", 0, NULL);
- if (videocodec_proc_entry) {
- videocodec_proc_entry->read_proc = videocodec_info;
- videocodec_proc_entry->write_proc = NULL;
- videocodec_proc_entry->data = NULL;
- videocodec_proc_entry->owner = THIS_MODULE;
- } else {
+ videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops);
+ if (!videocodec_proc_entry) {
dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
}
#endif
@@ -465,7 +391,6 @@ videocodec_exit (void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("videocodecs", NULL);
- kfree(videocodec_buf);
#endif
}
diff --git a/linux/drivers/media/video/videodev.c b/linux/drivers/media/video/videodev.c
index 43cdb1de5..d7059944b 100644
--- a/linux/drivers/media/video/videodev.c
+++ b/linux/drivers/media/video/videodev.c
@@ -18,14 +18,14 @@
#define dbgarg(cmd, fmt, arg...) \
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
- printk (KERN_DEBUG "%s: ", vfd->name); \
+ printk(KERN_DEBUG "%s: ", vfd->name); \
v4l_printk_ioctl(cmd); \
- printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \
+ printk(" " fmt, ## arg); \
}
#define dbgarg2(fmt, arg...) \
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
- printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+ printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
#include <linux/module.h>
#include <linux/types.h>
@@ -335,6 +335,7 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
[_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT",
+ [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK",
#endif
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -382,38 +383,45 @@ static const char *v4l2_int_ioctls[] = {
external ioctl messages as well as internal V4L ioctl */
void v4l_printk_ioctl(unsigned int cmd)
{
- char *dir;
+ char *dir, *type;
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE: dir = "--"; break;
- case _IOC_READ: dir = "r-"; break;
- case _IOC_WRITE: dir = "-w"; break;
- case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
- default: dir = "*ERR*"; break;
- }
switch (_IOC_TYPE(cmd)) {
case 'd':
- printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
- v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
+ if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) {
+ type = "v4l2_int";
+ break;
+ }
+ printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]);
+ return;
#ifdef CONFIG_VIDEO_V4L1_COMPAT
case 'v':
- printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L1_IOCTLS) ?
- v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
+ if (_IOC_NR(cmd) >= V4L1_IOCTLS) {
+ type = "v4l1";
+ break;
+ }
+ printk("%s", v4l1_ioctls[_IOC_NR(cmd)]);
+ return;
#endif
case 'V':
- printk("v4l2 ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L2_IOCTLS) ?
- v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
-
+ if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
+ type = "v4l2";
+ break;
+ }
+ printk("%s", v4l2_ioctls[_IOC_NR(cmd)]);
+ return;
default:
- printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n",
- _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
+ type = "unknown";
+ }
+
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE: dir = "--"; break;
+ case _IOC_READ: dir = "r-"; break;
+ case _IOC_WRITE: dir = "-w"; break;
+ case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+ default: dir = "*ERR*"; break;
}
+ printk("%s ioctl '%c', dir=%s, #%d (0x%08x)",
+ type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
}
EXPORT_SYMBOL(v4l_printk_ioctl);
@@ -762,35 +770,35 @@ static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
{
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (vfd->vidioc_try_fmt_cap)
+ if (vfd->vidioc_try_fmt_vid_cap)
return (0);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- if (vfd->vidioc_try_fmt_overlay)
+ if (vfd->vidioc_try_fmt_vid_overlay)
return (0);
break;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (vfd->vidioc_try_fmt_vbi)
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_try_fmt_vid_out)
return (0);
break;
- case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
- if (vfd->vidioc_try_fmt_vbi_output)
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+ if (vfd->vidioc_try_fmt_vid_out_overlay)
return (0);
break;
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- if (vfd->vidioc_try_fmt_vbi_capture)
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi_cap)
return (0);
break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- if (vfd->vidioc_try_fmt_video_output)
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_out)
return (0);
break;
- case V4L2_BUF_TYPE_VBI_OUTPUT:
- if (vfd->vidioc_try_fmt_vbi_output)
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_sliced_vbi_cap)
return (0);
break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
- if (vfd->vidioc_try_fmt_output_overlay)
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_sliced_vbi_out)
return (0);
break;
case V4L2_BUF_TYPE_PRIVATE:
@@ -811,6 +819,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
v4l_print_ioctl(vfd->name, cmd);
+ printk("\n");
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -906,46 +915,37 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (vfd->vidioc_enum_fmt_cap)
- ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
+ if (vfd->vidioc_enum_fmt_vid_cap)
+ ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- if (vfd->vidioc_enum_fmt_overlay)
- ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
+ if (vfd->vidioc_enum_fmt_vid_overlay)
+ ret = vfd->vidioc_enum_fmt_vid_overlay(file,
+ fh, f);
break;
+#if 1 /* keep */
+ /* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT
+ * according to the spec. The bttv and saa7134 drivers support
+ * it though, so just warn that this is deprecated and will be
+ * removed in the near future. */
case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (vfd->vidioc_enum_fmt_vbi)
- ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
- break;
- case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
- if (vfd->vidioc_enum_fmt_vbi_output)
- ret=vfd->vidioc_enum_fmt_vbi_output(file,
- fh, f);
- break;
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- if (vfd->vidioc_enum_fmt_vbi_capture)
- ret=vfd->vidioc_enum_fmt_vbi_capture(file,
- fh, f);
+ if (vfd->vidioc_enum_fmt_vbi_cap) {
+ printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n");
+ ret = vfd->vidioc_enum_fmt_vbi_cap(file, fh, f);
+ }
break;
+#endif
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- if (vfd->vidioc_enum_fmt_video_output)
- ret=vfd->vidioc_enum_fmt_video_output(file,
- fh, f);
- break;
- case V4L2_BUF_TYPE_VBI_OUTPUT:
- if (vfd->vidioc_enum_fmt_vbi_output)
- ret=vfd->vidioc_enum_fmt_vbi_output(file,
- fh, f);
- break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
- if (vfd->vidioc_enum_fmt_output_overlay)
- ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f);
+ if (vfd->vidioc_enum_fmt_vid_out)
+ ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f);
break;
case V4L2_BUF_TYPE_PRIVATE:
if (vfd->vidioc_enum_fmt_type_private)
- ret=vfd->vidioc_enum_fmt_type_private(file,
+ ret = vfd->vidioc_enum_fmt_type_private(file,
fh, f);
break;
+ default:
+ break;
}
if (!ret)
dbgarg (cmd, "index=%d, type=%d, flags=%d, "
@@ -961,54 +961,54 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_FMT:
{
struct v4l2_format *f = (struct v4l2_format *)arg;
- enum v4l2_buf_type type=f->type;
- memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
- f->type=type;
+ memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
/* FIXME: Should be one dump per type */
- dbgarg (cmd, "type=%s\n", prt_names(type,
- v4l2_type_names));
+ dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
- switch (type) {
+ switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (vfd->vidioc_g_fmt_cap)
- ret=vfd->vidioc_g_fmt_cap(file, fh, f);
+ if (vfd->vidioc_g_fmt_vid_cap)
+ ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f);
if (!ret)
v4l_print_pix_fmt(vfd,&f->fmt.pix);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- if (vfd->vidioc_g_fmt_overlay)
- ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
- break;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (vfd->vidioc_g_fmt_vbi)
- ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
- break;
- case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
- if (vfd->vidioc_g_fmt_vbi_output)
- ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
- break;
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- if (vfd->vidioc_g_fmt_vbi_capture)
- ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
+ if (vfd->vidioc_g_fmt_vid_overlay)
+ ret = vfd->vidioc_g_fmt_vid_overlay(file,
+ fh, f);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- if (vfd->vidioc_g_fmt_video_output)
- ret=vfd->vidioc_g_fmt_video_output(file,
- fh, f);
+ if (vfd->vidioc_g_fmt_vid_out)
+ ret = vfd->vidioc_g_fmt_vid_out(file, fh, f);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
- if (vfd->vidioc_g_fmt_output_overlay)
- ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f);
+ if (vfd->vidioc_g_fmt_vid_out_overlay)
+ ret = vfd->vidioc_g_fmt_vid_out_overlay(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_g_fmt_vbi_cap)
+ ret = vfd->vidioc_g_fmt_vbi_cap(file, fh, f);
break;
case V4L2_BUF_TYPE_VBI_OUTPUT:
- if (vfd->vidioc_g_fmt_vbi_output)
- ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+ if (vfd->vidioc_g_fmt_vbi_out)
+ ret = vfd->vidioc_g_fmt_vbi_out(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_g_fmt_sliced_vbi_cap)
+ ret = vfd->vidioc_g_fmt_sliced_vbi_cap(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_g_fmt_sliced_vbi_out)
+ ret = vfd->vidioc_g_fmt_sliced_vbi_out(file,
+ fh, f);
break;
case V4L2_BUF_TYPE_PRIVATE:
if (vfd->vidioc_g_fmt_type_private)
- ret=vfd->vidioc_g_fmt_type_private(file,
+ ret = vfd->vidioc_g_fmt_type_private(file,
fh, f);
break;
}
@@ -1026,42 +1026,44 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
v4l_print_pix_fmt(vfd,&f->fmt.pix);
- if (vfd->vidioc_s_fmt_cap)
- ret=vfd->vidioc_s_fmt_cap(file, fh, f);
+ if (vfd->vidioc_s_fmt_vid_cap)
+ ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- if (vfd->vidioc_s_fmt_overlay)
- ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
- break;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (vfd->vidioc_s_fmt_vbi)
- ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
- break;
- case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
- if (vfd->vidioc_s_fmt_vbi_output)
- ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
- break;
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- if (vfd->vidioc_s_fmt_vbi_capture)
- ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
+ if (vfd->vidioc_s_fmt_vid_overlay)
+ ret = vfd->vidioc_s_fmt_vid_overlay(file,
+ fh, f);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- if (vfd->vidioc_s_fmt_video_output)
- ret=vfd->vidioc_s_fmt_video_output(file,
- fh, f);
+ if (vfd->vidioc_s_fmt_vid_out)
+ ret = vfd->vidioc_s_fmt_vid_out(file, fh, f);
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
- if (vfd->vidioc_s_fmt_output_overlay)
- ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f);
+ if (vfd->vidioc_s_fmt_vid_out_overlay)
+ ret = vfd->vidioc_s_fmt_vid_out_overlay(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_s_fmt_vbi_cap)
+ ret = vfd->vidioc_s_fmt_vbi_cap(file, fh, f);
break;
case V4L2_BUF_TYPE_VBI_OUTPUT:
- if (vfd->vidioc_s_fmt_vbi_output)
- ret=vfd->vidioc_s_fmt_vbi_output(file,
- fh, f);
+ if (vfd->vidioc_s_fmt_vbi_out)
+ ret = vfd->vidioc_s_fmt_vbi_out(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_s_fmt_sliced_vbi_cap)
+ ret = vfd->vidioc_s_fmt_sliced_vbi_cap(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_s_fmt_sliced_vbi_out)
+ ret = vfd->vidioc_s_fmt_sliced_vbi_out(file,
+ fh, f);
break;
case V4L2_BUF_TYPE_PRIVATE:
if (vfd->vidioc_s_fmt_type_private)
- ret=vfd->vidioc_s_fmt_type_private(file,
+ ret = vfd->vidioc_s_fmt_type_private(file,
fh, f);
break;
}
@@ -1076,46 +1078,46 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
v4l2_type_names));
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (vfd->vidioc_try_fmt_cap)
- ret=vfd->vidioc_try_fmt_cap(file, fh, f);
+ if (vfd->vidioc_try_fmt_vid_cap)
+ ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f);
if (!ret)
v4l_print_pix_fmt(vfd,&f->fmt.pix);
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- if (vfd->vidioc_try_fmt_overlay)
- ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
+ if (vfd->vidioc_try_fmt_vid_overlay)
+ ret = vfd->vidioc_try_fmt_vid_overlay(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_try_fmt_vid_out)
+ ret = vfd->vidioc_try_fmt_vid_out(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+ if (vfd->vidioc_try_fmt_vid_out_overlay)
+ ret = vfd->vidioc_try_fmt_vid_out_overlay(file,
+ fh, f);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (vfd->vidioc_try_fmt_vbi)
- ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
+ if (vfd->vidioc_try_fmt_vbi_cap)
+ ret = vfd->vidioc_try_fmt_vbi_cap(file, fh, f);
break;
- case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
- if (vfd->vidioc_try_fmt_vbi_output)
- ret=vfd->vidioc_try_fmt_vbi_output(file,
- fh, f);
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_out)
+ ret = vfd->vidioc_try_fmt_vbi_out(file, fh, f);
break;
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- if (vfd->vidioc_try_fmt_vbi_capture)
- ret=vfd->vidioc_try_fmt_vbi_capture(file,
- fh, f);
- break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- if (vfd->vidioc_try_fmt_video_output)
- ret=vfd->vidioc_try_fmt_video_output(file,
+ if (vfd->vidioc_try_fmt_sliced_vbi_cap)
+ ret = vfd->vidioc_try_fmt_sliced_vbi_cap(file,
fh, f);
break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
- if (vfd->vidioc_try_fmt_output_overlay)
- ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f);
- break;
- case V4L2_BUF_TYPE_VBI_OUTPUT:
- if (vfd->vidioc_try_fmt_vbi_output)
- ret=vfd->vidioc_try_fmt_vbi_output(file,
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_sliced_vbi_out)
+ ret = vfd->vidioc_try_fmt_sliced_vbi_out(file,
fh, f);
break;
case V4L2_BUF_TYPE_PRIVATE:
if (vfd->vidioc_try_fmt_type_private)
- ret=vfd->vidioc_try_fmt_type_private(file,
+ ret = vfd->vidioc_try_fmt_type_private(file,
fh, f);
break;
}
@@ -1342,11 +1344,15 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
{
v4l2_std_id *id = arg;
- *id = vfd->current_norm;
-
- dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
+ ret = 0;
+ /* Calls the specific handler */
+ if (vfd->vidioc_g_std)
+ ret = vfd->vidioc_g_std(file, fh, id);
+ else
+ *id = vfd->current_norm;
- ret=0;
+ if (!ret)
+ dbgarg(cmd, "value=%08Lx\n", (long long unsigned)*id);
break;
}
case VIDIOC_S_STD:
@@ -1429,6 +1435,25 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
}
/* ------ output switching ---------- */
+ case VIDIOC_ENUMOUTPUT:
+ {
+ struct v4l2_output *p = arg;
+ int i = p->index;
+
+ if (!vfd->vidioc_enum_output)
+ break;
+ memset(p, 0, sizeof(*p));
+ p->index = i;
+
+ ret = vfd->vidioc_enum_output(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "index=%d, name=%s, type=%d, "
+ "audioset=%d, "
+ "modulator=%d, std=%08Lx\n",
+ p->index, p->name, p->type, p->audioset,
+ p->modulator, (unsigned long long)p->std);
+ break;
+ }
case VIDIOC_G_OUTPUT:
{
unsigned int *i = arg;
@@ -1821,16 +1846,17 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOC_G_FREQUENCY:
{
- struct v4l2_frequency *p=arg;
+ struct v4l2_frequency *p = arg;
+
if (!vfd->vidioc_g_frequency)
break;
- memset(p,0,sizeof(*p));
+ memset(p->reserved, 0, sizeof(p->reserved));
- ret=vfd->vidioc_g_frequency(file, fh, p);
+ ret = vfd->vidioc_g_frequency(file, fh, p);
if (!ret)
- dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
- p->tuner,p->type,p->frequency);
+ dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
+ p->tuner, p->type, p->frequency);
break;
}
case VIDIOC_S_FREQUENCY:
@@ -1890,12 +1916,31 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
break;
}
+ default:
+ {
+ if (!vfd->vidioc_default)
+ break;
+ ret = vfd->vidioc_default(file, fh, cmd, arg);
+ break;
+ }
+ case VIDIOC_S_HW_FREQ_SEEK:
+ {
+ struct v4l2_hw_freq_seek *p = arg;
+ if (!vfd->vidioc_s_hw_freq_seek)
+ break;
+ dbgarg(cmd,
+ "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n",
+ p->tuner, p->type, p->seek_upward, p->wrap_around);
+ ret = vfd->vidioc_s_hw_freq_seek(file, fh, p);
+ break;
+ }
} /* switch */
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
if (ret<0) {
- printk ("%s: err:\n", vfd->name);
+ printk("%s: err: on ", vfd->name);
v4l_print_ioctl(vfd->name, cmd);
+ printk("\n");
}
}
@@ -2056,7 +2101,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
break;
default:
printk(KERN_ERR "%s called with unknown type: %d\n",
- __FUNCTION__, type);
+ __func__, type);
return -1;
}
@@ -2105,7 +2150,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
ret = device_register(&vfd->class_dev);
if (ret < 0) {
printk(KERN_ERR "%s: device_register failed\n",
- __FUNCTION__);
+ __func__);
goto fail_minor;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c
index ef7752aa8..bf15e2eb2 100644
--- a/linux/drivers/media/video/vino.c
+++ b/linux/drivers/media/video/vino.c
@@ -13,7 +13,7 @@
/*
* TODO:
* - remove "mark pages reserved-hacks" from memory allocation code
- * and implement nopage()
+ * and implement fault()
* - check decimation, calculating and reporting image size when
* using decimation
* - implement read(), user mode buffers and overlay (?)
diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c
index 6464c69f3..028040dd8 100644
--- a/linux/drivers/media/video/vivi.c
+++ b/linux/drivers/media/video/vivi.c
@@ -439,7 +439,7 @@ static void vivi_sleep(struct vivi_fh *fh)
int timeout;
DECLARE_WAITQUEUE(wait, current);
- dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
+ dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
(unsigned long)dma_q);
add_wait_queue(&dma_q->wq, &wait);
@@ -514,7 +514,7 @@ static int vivi_start_thread(struct vivi_fh *fh)
dma_q->frame = 0;
dma_q->ini_jiffies = jiffies;
- dprintk(dev, 1, "%s\n", __FUNCTION__);
+ dprintk(dev, 1, "%s\n", __func__);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
@@ -541,7 +541,7 @@ static int vivi_start_thread(struct vivi_fh *fh)
/* Wakes thread */
wake_up_interruptible(&dma_q->wq);
- dprintk(dev, 1, "returning from %s\n", __FUNCTION__);
+ dprintk(dev, 1, "returning from %s\n", __func__);
return 0;
}
@@ -549,7 +549,7 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
{
struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
- dprintk(dev, 1, "%s\n", __FUNCTION__);
+ dprintk(dev, 1, "%s\n", __func__);
/* shutdown control thread */
if (dma_q->kthread) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
@@ -586,7 +586,7 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
while (*size * *count > vid_limit * 1024 * 1024)
(*count)--;
- dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__,
+ dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
*count, *size);
return 0;
@@ -597,13 +597,13 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
struct vivi_fh *fh = vq->priv_data;
struct vivi_dev *dev = fh->dev;
- dprintk(dev, 1, "%s, state: %i\n", __FUNCTION__, buf->vb.state);
+ dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
if (in_interrupt())
BUG();
videobuf_vmalloc_free(&buf->vb);
- dprintk(dev, 1, "free_buffer: freed");
+ dprintk(dev, 1, "free_buffer: freed\n");
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
@@ -618,7 +618,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
int rc;
- dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field);
+ dprintk(dev, 1, "%s, field=%d\n", __func__, field);
BUG_ON(NULL == fh->fmt);
@@ -659,7 +659,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *vidq = &dev->vidq;
- dprintk(dev, 1, "%s\n", __FUNCTION__);
+ dprintk(dev, 1, "%s\n", __func__);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue, &vidq->active);
@@ -672,7 +672,7 @@ static void buffer_release(struct videobuf_queue *vq,
struct vivi_fh *fh = vq->priv_data;
struct vivi_dev *dev = (struct vivi_dev *)fh->dev;
- dprintk(dev, 1, "%s\n", __FUNCTION__);
+ dprintk(dev, 1, "%s\n", __func__);
free_buffer(vq, buf);
}
@@ -699,7 +699,7 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_fmt_cap(struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (f->index > 0)
@@ -710,7 +710,7 @@ static int vidioc_enum_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_g_fmt_cap(struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_fh *fh = priv;
@@ -727,7 +727,7 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv,
return (0);
}
-static int vidioc_try_fmt_cap(struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_fh *fh = priv;
@@ -775,20 +775,20 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv,
}
/*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_cap(struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_fh *fh = priv;
struct videobuf_queue *q = &fh->vb_vidq;
- int ret = vidioc_try_fmt_cap(file, fh, f);
+ int ret = vidioc_try_fmt_vid_cap(file, fh, f);
if (ret < 0)
return (ret);
mutex_lock(&q->vb_lock);
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- dprintk(fh->dev, 1, "%s queue busy\n", __FUNCTION__);
+ dprintk(fh->dev, 1, "%s queue busy\n", __func__);
ret = -EBUSY;
goto out;
}
@@ -958,7 +958,7 @@ static int vivi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
struct vivi_dev *dev;
- struct vivi_fh *fh;
+ struct vivi_fh *fh = NULL;
int i;
int retval = 0;
@@ -1044,7 +1044,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
struct vivi_dev *dev = fh->dev;
struct videobuf_queue *q = &fh->vb_vidq;
- dprintk(dev, 1, "%s\n", __FUNCTION__);
+ dprintk(dev, 1, "%s\n", __func__);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
return POLLERR;
@@ -1123,7 +1123,7 @@ static const struct file_operations vivi_fops = {
.poll = vivi_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
- .compat_ioctl = v4l_compat_ioctl32,
+ .compat_ioctl = v4l_compat_ioctl32,
#endif
.mmap = vivi_mmap,
.llseek = no_llseek,
@@ -1137,10 +1137,10 @@ static struct video_device vivi_template = {
.release = video_device_release,
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
- .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
- .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
diff --git a/linux/drivers/media/video/vp27smpx.c b/linux/drivers/media/video/vp27smpx.c
index 922aa8d74..25a69c7f5 100644
--- a/linux/drivers/media/video/vp27smpx.c
+++ b/linux/drivers/media/video/vp27smpx.c
@@ -135,7 +135,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int vp27smpx_probe(struct i2c_client *client)
+static int vp27smpx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct vp27smpx_state *state;
@@ -143,8 +144,9 @@ static int vp27smpx_probe(struct i2c_client *client)
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
-
+#endif
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -167,6 +169,14 @@ static int vp27smpx_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id vp27smpx_id[] = {
+ { "vp27smpx", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vp27smpx_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "vp27smpx",
.driverid = I2C_DRIVERID_VP27SMPX,
@@ -176,6 +186,9 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
#ifndef I2C_CLASS_TV_ANALOG
.legacy_id = I2C_HW_B_CX2341X,
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = vp27smpx_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/w9966.c b/linux/drivers/media/video/w9966.c
index 595e32a87..9b77f268c 100644
--- a/linux/drivers/media/video/w9966.c
+++ b/linux/drivers/media/video/w9966.c
@@ -65,7 +65,7 @@
/*#define DEBUG*/ /* Undef me for production */
#ifdef DEBUG
-#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __FUNCTION__ , ##a)
+#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
#else
#define DPRINTF(x...)
#endif
diff --git a/linux/drivers/media/video/w9968cf.h b/linux/drivers/media/video/w9968cf.h
index c2e609bac..8e1742cb7 100644
--- a/linux/drivers/media/video/w9968cf.h
+++ b/linux/drivers/media/video/w9968cf.h
@@ -304,7 +304,7 @@ struct w9968cf_device {
dev_warn(&cam->dev, fmt "\n", ## args); \
else if ((level) >= 5) \
dev_info(&cam->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
}
/* For generic kernel (not device specific) messages */
@@ -315,7 +315,7 @@ struct w9968cf_device {
if ((level) >= 1 && (level) <= 4) \
pr_info("w9968cf: " fmt "\n", ## args); \
else if ((level) >= 5) \
- pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__, \
+ pr_debug("w9968cf: [%s:%d] " fmt "\n", __func__, \
__LINE__ , ## args); \
} \
}
@@ -327,7 +327,7 @@ struct w9968cf_device {
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
+dev_info(&cam->dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
diff --git a/linux/drivers/media/video/wm8739.c b/linux/drivers/media/video/wm8739.c
index f2010b8a7..d448dcf6e 100644
--- a/linux/drivers/media/video/wm8739.c
+++ b/linux/drivers/media/video/wm8739.c
@@ -279,7 +279,8 @@ static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
/* i2c implementation */
-static int wm8739_probe(struct i2c_client *client)
+static int wm8739_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct wm8739_state *state;
@@ -330,6 +331,14 @@ static int wm8739_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id wm8739_id[] = {
+ { "wm8739", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8739_id);
+#endif
+
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "wm8739",
.driverid = I2C_DRIVERID_WM8739,
@@ -339,6 +348,9 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
#ifndef I2C_CLASS_TV_ANALOG
.legacy_id = I2C_HW_B_CX2341X,
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = wm8739_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/wm8775.c b/linux/drivers/media/video/wm8775.c
index b0030789b..81a08d674 100644
--- a/linux/drivers/media/video/wm8775.c
+++ b/linux/drivers/media/video/wm8775.c
@@ -167,7 +167,8 @@ static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int wm8775_probe(struct i2c_client *client)
+static int wm8775_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct wm8775_state *state;
@@ -223,12 +224,23 @@ static int wm8775_remove(struct i2c_client *client)
return 0;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+static const struct i2c_device_id wm8775_id[] = {
+ { "wm8775", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8775_id);
+
+#endif
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "wm8775",
.driverid = I2C_DRIVERID_WM8775,
.command = wm8775_command,
.probe = wm8775_probe,
.remove = wm8775_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
+ .id_table = wm8775_id,
+#endif
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
diff --git a/linux/drivers/media/video/zc0301/zc0301.h b/linux/drivers/media/video/zc0301/zc0301.h
index 6a944c658..d0e258176 100644
--- a/linux/drivers/media/video/zc0301/zc0301.h
+++ b/linux/drivers/media/video/zc0301/zc0301.h
@@ -167,7 +167,7 @@ do { \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
- __FILE__, __FUNCTION__, __LINE__ , ## args); \
+ __FILE__, __func__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -177,7 +177,7 @@ do { \
pr_info("zc0301: " fmt "\n", ## args); \
else if ((level) == 3) \
pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -193,7 +193,7 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
__LINE__ , ## args)
#undef PDBGG
diff --git a/linux/drivers/media/video/zc0301/zc0301_core.c b/linux/drivers/media/video/zc0301/zc0301_core.c
index 261964c6a..e167fa560 100644
--- a/linux/drivers/media/video/zc0301/zc0301_core.c
+++ b/linux/drivers/media/video/zc0301/zc0301_core.c
@@ -38,7 +38,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
+#include <asm/byteorder.h>
#include <asm/page.h>
#include <asm/uaccess.h>
diff --git a/linux/drivers/media/video/zoran.h b/linux/drivers/media/video/zoran.h
index 848dbcf25..baa5f423d 100644
--- a/linux/drivers/media/video/zoran.h
+++ b/linux/drivers/media/video/zoran.h
@@ -243,10 +243,8 @@ struct zoran_format {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
int palette;
#endif
-#ifdef CONFIG_VIDEO_V4L2
__u32 fourcc;
int colorspace;
-#endif
int depth;
__u32 flags;
__u32 vfespfr;
@@ -271,20 +269,6 @@ struct zoran_v4l_settings {
const struct zoran_format *format; /* capture format */
};
-/* whoops, this one is undeclared if !v4l2 */
-#ifndef CONFIG_VIDEO_V4L2
-struct v4l2_jpegcompression {
- int quality;
- int APPn;
- int APP_len;
- char APP_data[60];
- int COM_len;
- char COM_data[60];
- __u32 jpeg_markers;
- __u8 reserved[116];
-};
-#endif
-
/* jpg-capture/-playback settings */
struct zoran_jpg_settings {
int decimation; /* this bit is used to set everything to default */
@@ -301,7 +285,7 @@ struct zoran_mapping {
struct zoran_jpg_buffer {
struct zoran_mapping *map;
- u32 *frag_tab; /* addresses of frag table */
+ __le32 *frag_tab; /* addresses of frag table */
u32 frag_tab_bus; /* same value cached to save time in ISR */
enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */
struct zoran_sync bs; /* DONE: info to return to application */
@@ -470,7 +454,7 @@ struct zoran {
unsigned long jpg_queued_num; /* count of frames queued since grab/play started */
/* zr36057's code buffer table */
- u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+ __le32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
/* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
int jpg_pend[BUZ_MAX_FRAME];
diff --git a/linux/drivers/media/video/zoran_device.c b/linux/drivers/media/video/zoran_device.c
index 575f5447c..b0a014d09 100644
--- a/linux/drivers/media/video/zoran_device.c
+++ b/linux/drivers/media/video/zoran_device.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
-#include <linux/byteorder/generic.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
@@ -48,6 +47,7 @@
#include <linux/delay.h>
#include <linux/wait.h>
+#include <asm/byteorder.h>
#include <asm/io.h>
#include "videocodec.h"
@@ -1321,7 +1321,7 @@ error_handler (struct zoran *zr,
if (i) {
/* Rotate stat_comm entries to make current entry first */
int j;
- u32 bus_addr[BUZ_NUM_STAT_COM];
+ __le32 bus_addr[BUZ_NUM_STAT_COM];
/* Here we are copying the stat_com array, which
* is already in little endian format, so
diff --git a/linux/drivers/media/video/zoran_driver.c b/linux/drivers/media/video/zoran_driver.c
index ceb5c1778..fdec02d98 100644
--- a/linux/drivers/media/video/zoran_driver.c
+++ b/linux/drivers/media/video/zoran_driver.c
@@ -52,7 +52,6 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
-#include <linux/byteorder/generic.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
@@ -74,6 +73,7 @@
#include <media/v4l2-common.h>
#include "videocodec.h"
+#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
@@ -88,7 +88,6 @@
#include "zoran_device.h"
#include "zoran_card.h"
-#ifdef CONFIG_VIDEO_V4L2
/* we declare some card type definitions here, they mean
* the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */
#define ZORAN_V4L2_VID_FLAGS ( \
@@ -97,19 +96,15 @@
V4L2_CAP_VIDEO_OUTPUT |\
V4L2_CAP_VIDEO_OVERLAY \
)
-#endif
#include <asm/byteorder.h>
-#if defined(CONFIG_VIDEO_V4L2) && defined(CONFIG_VIDEO_V4L1_COMPAT)
+#if defined(CONFIG_VIDEO_V4L1_COMPAT)
#define ZFMT(pal, fcc, cs) \
.palette = (pal), .fourcc = (fcc), .colorspace = (cs)
-#elif defined(CONFIG_VIDEO_V4L2)
-#define ZFMT(pal, fcc, cs) \
- .fourcc = (fcc), .colorspace = (cs)
#else
#define ZFMT(pal, fcc, cs) \
- .palette = (pal)
+ .fourcc = (fcc), .colorspace = (cs)
#endif
const struct zoran_format zoran_formats[] = {
@@ -219,7 +214,6 @@ static int lock_norm; /* 0 = default 1 = Don't change TV standard (norm) */
module_param(lock_norm, int, 0644);
MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
-#ifdef CONFIG_VIDEO_V4L2
/* small helper function for calculating buffersizes for v4l2
* we calculate the nearest higher power-of-two, which
* will be the recommended buffersize */
@@ -242,7 +236,6 @@ zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
return 8192;
return result;
}
-#endif
/* forward references */
static void v4l_fbuffer_free(struct file *file);
@@ -353,7 +346,7 @@ v4l_fbuffer_alloc (struct file *file)
/* Use kmalloc */
mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
- if (mem == 0) {
+ if (!mem) {
dprintk(1,
KERN_ERR
"%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n",
@@ -569,7 +562,7 @@ jpg_fbuffer_alloc (struct file *file)
jpg_fbuffer_free(file);
return -ENOBUFS;
}
- fh->jpg_buffers.buffer[i].frag_tab = (u32 *) mem;
+ fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem;
fh->jpg_buffers.buffer[i].frag_tab_bus =
virt_to_bus((void *) mem);
@@ -1241,7 +1234,7 @@ zoran_close_end_session (struct file *file)
/* v4l capture */
if (fh->v4l_buffers.active != ZORAN_FREE) {
- long flags;
+ unsigned long flags;
spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
@@ -1776,7 +1769,6 @@ setup_overlay (struct file *file,
return wait_grab_pending(zr);
}
-#ifdef CONFIG_VIDEO_V4L2
/* get the status of a buffer in the clients buffer queue */
static int
zoran_v4l2_buffer_status (struct file *file,
@@ -1882,7 +1874,6 @@ zoran_v4l2_buffer_status (struct file *file,
return 0;
}
-#endif
static int
zoran_set_norm (struct zoran *zr,
@@ -2691,8 +2682,6 @@ zoran_do_ioctl (struct inode *inode,
}
break;
-#ifdef CONFIG_VIDEO_V4L2
-
/* The new video4linux2 capture interface - much nicer than video4linux1, since
* it allows for integrating the JPEG capturing calls inside standard v4l2
*/
@@ -3514,7 +3503,7 @@ zoran_do_ioctl (struct inode *inode,
/* unload capture */
if (zr->v4l_memgrab_active) {
- long flags;
+ unsigned long flags;
spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
@@ -4264,7 +4253,6 @@ zoran_do_ioctl (struct inode *inode,
return 0;
}
break;
-#endif
default:
dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
@@ -4314,7 +4302,7 @@ zoran_poll (struct file *file,
dprintk(3,
KERN_DEBUG
"%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
- ZR_DEVNAME(zr), __FUNCTION__,
+ ZR_DEVNAME(zr), __func__,
"FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
"UPMD"[zr->v4l_buffers.buffer[frame].state],
zr->v4l_pend_tail, zr->v4l_pend_head);
@@ -4336,7 +4324,7 @@ zoran_poll (struct file *file,
dprintk(3,
KERN_DEBUG
"%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
- ZR_DEVNAME(zr), __FUNCTION__,
+ ZR_DEVNAME(zr), __func__,
"FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
"UPMD"[zr->jpg_buffers.buffer[frame].state],
zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
@@ -4454,7 +4442,7 @@ zoran_vm_close (struct vm_area_struct *vma)
mutex_lock(&zr->resource_lock);
if (fh->v4l_buffers.active != ZORAN_FREE) {
- long flags;
+ unsigned long flags;
spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
@@ -4585,7 +4573,7 @@ zoran_mmap (struct file *file,
if (todo > fraglen)
todo = fraglen;
pos =
- le32_to_cpu((unsigned long) fh->jpg_buffers.
+ le32_to_cpu(fh->jpg_buffers.
buffer[i].frag_tab[2 * j]);
/* should just be pos on i386 */
page = virt_to_phys(bus_to_virt(pos))
@@ -4724,9 +4712,7 @@ static const struct file_operations zoran_fops = {
struct video_device zoran_template __devinitdata = {
.name = ZORAN_NAME,
.type = ZORAN_VID_TYPE,
-#ifdef CONFIG_VIDEO_V4L2
.type2 = ZORAN_V4L2_VID_FLAGS,
-#endif
.fops = &zoran_fops,
.release = &zoran_vdev_release,
.minor = -1
diff --git a/linux/drivers/media/video/zoran_procfs.c b/linux/drivers/media/video/zoran_procfs.c
index 5aa285bdc..d7bc097da 100644
--- a/linux/drivers/media/video/zoran_procfs.c
+++ b/linux/drivers/media/video/zoran_procfs.c
@@ -189,6 +189,7 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer,
}
static const struct file_operations zoran_operations = {
+ .owner = THIS_MODULE,
.open = zoran_open,
.read = seq_read,
.write = zoran_write,
@@ -204,10 +205,8 @@ zoran_proc_init (struct zoran *zr)
char name[8];
snprintf(name, 7, "zoran%d", zr->id);
- if ((zr->zoran_proc = create_proc_entry(name, 0, NULL))) {
- zr->zoran_proc->data = zr;
- zr->zoran_proc->owner = THIS_MODULE;
- zr->zoran_proc->proc_fops = &zoran_operations;
+ zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr);
+ if (zr->zoran_proc != NULL) {
dprintk(2,
KERN_INFO
"%s: procfs entry /proc/%s allocated. data=%p\n",
diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c
index 0afd1c9c1..2e7cf6f26 100644
--- a/linux/drivers/media/video/zr364xx.c
+++ b/linux/drivers/media/video/zr364xx.c
@@ -395,7 +395,7 @@ static int read_frame(struct zr364xx_camera *cam, int framenum)
}
-static ssize_t zr364xx_read(struct file *file, char *buf, size_t cnt,
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
loff_t * ppos)
{
unsigned long count = cnt;
@@ -526,7 +526,7 @@ static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
return 0;
}
-static int zr364xx_vidioc_enum_fmt_cap(struct file *file,
+static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
void *priv, struct v4l2_fmtdesc *f)
{
if (f->index > 0)
@@ -542,7 +542,7 @@ static int zr364xx_vidioc_enum_fmt_cap(struct file *file,
return 0;
}
-static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv,
+static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct video_device *vdev = video_devdata(file);
@@ -569,7 +569,7 @@ static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv,
+static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct video_device *vdev = video_devdata(file);
@@ -594,7 +594,7 @@ static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv,
return 0;
}
-static int zr364xx_vidioc_s_fmt_cap(struct file *file, void *priv,
+static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct video_device *vdev = video_devdata(file);
@@ -775,10 +775,10 @@ static struct video_device zr364xx_template = {
.minor = -1,
.vidioc_querycap = zr364xx_vidioc_querycap,
- .vidioc_enum_fmt_cap = zr364xx_vidioc_enum_fmt_cap,
- .vidioc_try_fmt_cap = zr364xx_vidioc_try_fmt_cap,
- .vidioc_s_fmt_cap = zr364xx_vidioc_s_fmt_cap,
- .vidioc_g_fmt_cap = zr364xx_vidioc_g_fmt_cap,
+ .vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = zr364xx_vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = zr364xx_vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = zr364xx_vidioc_g_fmt_vid_cap,
.vidioc_enum_input = zr364xx_vidioc_enum_input,
.vidioc_g_input = zr364xx_vidioc_g_input,
.vidioc_s_input = zr364xx_vidioc_s_input,