diff options
Diffstat (limited to 'drivers/media/video/saa7134')
-rw-r--r-- | drivers/media/video/saa7134/Kconfig | 13 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa6752hs.c | 581 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-alsa.c | 8 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-cards.c | 333 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-core.c | 108 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-dvb.c | 75 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-empress.c | 27 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-i2c.c | 23 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-ts.c | 15 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-video.c | 75 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134.h | 40 |
11 files changed, 886 insertions, 412 deletions
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index fc2164e28e7..0ba68987bfc 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -6,6 +6,7 @@ config VIDEO_SAA7134 select VIDEO_TUNER select VIDEO_TVEEPROM select CRC32 + select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO ---help--- This is a video4linux driver for Philips SAA713x based TV cards. @@ -35,8 +36,16 @@ config VIDEO_SAA7134_DVB select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE - select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE + select DVB_ISL6405 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE + select DVB_ZL10036 if !DVB_FE_CUSTOMISE + select DVB_MT312 if !DVB_FE_CUSTOMISE + select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 1fee6e84a51..dc2213e2f86 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -33,9 +33,10 @@ #include <linux/i2c.h> #include <linux/types.h> #include <linux/videodev2.h> +#include <media/v4l2-device.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> -#include <media/v4l2-i2c-drv-legacy.h> +#include <media/v4l2-i2c-drv.h> #include <linux/init.h> #include <linux/crc32.h> @@ -44,10 +45,6 @@ #define MPEG_TOTAL_TARGET_BITRATE_MAX 27000 #define MPEG_PID_MAX ((1 << 14) - 1) -/* Addresses to scan */ -static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; - -I2C_CLIENT_INSMOD; MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); MODULE_AUTHOR("Andrew de Quincey"); @@ -95,6 +92,7 @@ static const struct v4l2_format v4l2_format_table[] = }; struct saa6752hs_state { + struct v4l2_subdev sd; int chip; u32 revision; int has_ac3; @@ -115,6 +113,11 @@ enum saa6752hs_command { SAA6752HS_COMMAND_MAX }; +static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct saa6752hs_state, sd); +} + /* ---------------------------------------------------------------------- */ static u8 PAT[] = { @@ -360,185 +363,191 @@ static int saa6752hs_set_bitrate(struct i2c_client *client, return 0; } -static void saa6752hs_set_subsampling(struct i2c_client *client, - struct v4l2_format *f) -{ - struct saa6752hs_state *h = i2c_get_clientdata(client); - int dist_352, dist_480, dist_720; - - /* - FIXME: translate and round width/height into EMPRESS - subsample type: - type | PAL | NTSC - --------------------------- - SIF | 352x288 | 352x240 - 1/2 D1 | 352x576 | 352x480 - 2/3 D1 | 480x576 | 480x480 - D1 | 720x576 | 720x480 - */ - - dist_352 = abs(f->fmt.pix.width - 352); - dist_480 = abs(f->fmt.pix.width - 480); - dist_720 = abs(f->fmt.pix.width - 720); - if (dist_720 < dist_480) { - f->fmt.pix.width = 720; - f->fmt.pix.height = 576; - h->video_format = SAA6752HS_VF_D1; - } - else if (dist_480 < dist_352) { - f->fmt.pix.width = 480; - f->fmt.pix.height = 576; - h->video_format = SAA6752HS_VF_2_3_D1; - } - else { - f->fmt.pix.width = 352; - if (abs(f->fmt.pix.height - 576) < - abs(f->fmt.pix.height - 288)) { - f->fmt.pix.height = 576; - h->video_format = SAA6752HS_VF_1_2_D1; - } - else { - f->fmt.pix.height = 288; - h->video_format = SAA6752HS_VF_SIF; - } +static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params, + struct v4l2_ext_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_MPEG_STREAM_TYPE: + ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; + break; + case V4L2_CID_MPEG_STREAM_PID_PMT: + ctrl->value = params->ts_pid_pmt; + break; + case V4L2_CID_MPEG_STREAM_PID_AUDIO: + ctrl->value = params->ts_pid_audio; + break; + case V4L2_CID_MPEG_STREAM_PID_VIDEO: + ctrl->value = params->ts_pid_video; + break; + case V4L2_CID_MPEG_STREAM_PID_PCR: + ctrl->value = params->ts_pid_pcr; + break; + case V4L2_CID_MPEG_AUDIO_ENCODING: + ctrl->value = params->au_encoding; + break; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + ctrl->value = params->au_l2_bitrate; + break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (!has_ac3) + return -EINVAL; + ctrl->value = params->au_ac3_bitrate; + break; + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + break; + case V4L2_CID_MPEG_VIDEO_ASPECT: + ctrl->value = params->vi_aspect; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctrl->value = params->vi_bitrate * 1000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + ctrl->value = params->vi_bitrate_peak * 1000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + ctrl->value = params->vi_bitrate_mode; + break; + default: + return -EINVAL; } + return 0; } - static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params, - struct v4l2_ext_control *ctrl, unsigned int cmd) + struct v4l2_ext_control *ctrl, int set) { int old = 0, new; - int set = (cmd == VIDIOC_S_EXT_CTRLS); new = ctrl->value; switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_STREAM_PID_PMT: - old = params->ts_pid_pmt; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_pmt = new; - break; - case V4L2_CID_MPEG_STREAM_PID_AUDIO: - old = params->ts_pid_audio; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_audio = new; - break; - case V4L2_CID_MPEG_STREAM_PID_VIDEO: - old = params->ts_pid_video; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_video = new; - break; - case V4L2_CID_MPEG_STREAM_PID_PCR: - old = params->ts_pid_pcr; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_pcr = new; - break; - case V4L2_CID_MPEG_AUDIO_ENCODING: - old = params->au_encoding; - if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && - (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3)) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - old = params->au_l2_bitrate; - if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K && - new != V4L2_MPEG_AUDIO_L2_BITRATE_384K) - return -ERANGE; - if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K) - new = V4L2_MPEG_AUDIO_L2_BITRATE_256K; - else - new = V4L2_MPEG_AUDIO_L2_BITRATE_384K; - params->au_l2_bitrate = new; - break; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - if (!has_ac3) - return -EINVAL; - old = params->au_ac3_bitrate; - if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K && - new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K) - return -ERANGE; - if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K) - new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K; - else - new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K; - params->au_ac3_bitrate = new; - break; - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - old = params->vi_aspect; - if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 && - new != V4L2_MPEG_VIDEO_ASPECT_4x3) - return -ERANGE; - if (new != V4L2_MPEG_VIDEO_ASPECT_16x9) - new = V4L2_MPEG_VIDEO_ASPECT_4x3; - params->vi_aspect = new; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - old = params->vi_bitrate * 1000; - new = 1000 * (new / 1000); - if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - return -ERANGE; - if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; - params->vi_bitrate = new / 1000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - old = params->vi_bitrate_peak * 1000; - new = 1000 * (new / 1000); - if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - return -ERANGE; - if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; - params->vi_bitrate_peak = new / 1000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - old = params->vi_bitrate_mode; - params->vi_bitrate_mode = new; - break; - default: + case V4L2_CID_MPEG_STREAM_TYPE: + old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; + if (set && new != old) + return -ERANGE; + new = old; + break; + case V4L2_CID_MPEG_STREAM_PID_PMT: + old = params->ts_pid_pmt; + if (set && new > MPEG_PID_MAX) + return -ERANGE; + if (new > MPEG_PID_MAX) + new = MPEG_PID_MAX; + params->ts_pid_pmt = new; + break; + case V4L2_CID_MPEG_STREAM_PID_AUDIO: + old = params->ts_pid_audio; + if (set && new > MPEG_PID_MAX) + return -ERANGE; + if (new > MPEG_PID_MAX) + new = MPEG_PID_MAX; + params->ts_pid_audio = new; + break; + case V4L2_CID_MPEG_STREAM_PID_VIDEO: + old = params->ts_pid_video; + if (set && new > MPEG_PID_MAX) + return -ERANGE; + if (new > MPEG_PID_MAX) + new = MPEG_PID_MAX; + params->ts_pid_video = new; + break; + case V4L2_CID_MPEG_STREAM_PID_PCR: + old = params->ts_pid_pcr; + if (set && new > MPEG_PID_MAX) + return -ERANGE; + if (new > MPEG_PID_MAX) + new = MPEG_PID_MAX; + params->ts_pid_pcr = new; + break; + case V4L2_CID_MPEG_AUDIO_ENCODING: + old = params->au_encoding; + if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && + (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3)) + return -ERANGE; + new = old; + break; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + old = params->au_l2_bitrate; + if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K && + new != V4L2_MPEG_AUDIO_L2_BITRATE_384K) + return -ERANGE; + if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K) + new = V4L2_MPEG_AUDIO_L2_BITRATE_256K; + else + new = V4L2_MPEG_AUDIO_L2_BITRATE_384K; + params->au_l2_bitrate = new; + break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (!has_ac3) return -EINVAL; + old = params->au_ac3_bitrate; + if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K && + new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K) + return -ERANGE; + if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K) + new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K; + else + new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K; + params->au_ac3_bitrate = new; + break; + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; + if (set && new != old) + return -ERANGE; + new = old; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (set && new != old) + return -ERANGE; + new = old; + break; + case V4L2_CID_MPEG_VIDEO_ASPECT: + old = params->vi_aspect; + if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 && + new != V4L2_MPEG_VIDEO_ASPECT_4x3) + return -ERANGE; + if (new != V4L2_MPEG_VIDEO_ASPECT_16x9) + new = V4L2_MPEG_VIDEO_ASPECT_4x3; + params->vi_aspect = new; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + old = params->vi_bitrate * 1000; + new = 1000 * (new / 1000); + if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) + return -ERANGE; + if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) + new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; + params->vi_bitrate = new / 1000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + old = params->vi_bitrate_peak * 1000; + new = 1000 * (new / 1000); + if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) + return -ERANGE; + if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) + new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; + params->vi_bitrate_peak = new / 1000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + old = params->vi_bitrate_mode; + params->vi_bitrate_mode = new; + break; + default: + return -EINVAL; } - if (cmd == VIDIOC_G_EXT_CTRLS) - ctrl->value = old; - else - ctrl->value = new; + ctrl->value = new; return 0; } -static int saa6752hs_qctrl(struct saa6752hs_state *h, - struct v4l2_queryctrl *qctrl) + +static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) { + struct saa6752hs_state *h = to_state(sd); struct saa6752hs_mpeg_params *params = &h->params; int err; @@ -583,7 +592,7 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h, V4L2_MPEG_VIDEO_ASPECT_4x3); case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - err = v4l2_ctrl_query_fill_std(qctrl); + err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); if (err == 0 && params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) @@ -597,12 +606,20 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h, V4L2_MPEG_STREAM_TYPE_MPEG2_TS); case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); case V4L2_CID_MPEG_VIDEO_BITRATE: + return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); case V4L2_CID_MPEG_STREAM_PID_PMT: + return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16); case V4L2_CID_MPEG_STREAM_PID_AUDIO: + return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260); case V4L2_CID_MPEG_STREAM_PID_VIDEO: + return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256); case V4L2_CID_MPEG_STREAM_PID_PCR: - return v4l2_ctrl_query_fill_std(qctrl); + return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259); default: break; @@ -610,8 +627,7 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h, return -EINVAL; } -static int saa6752hs_qmenu(struct saa6752hs_state *h, - struct v4l2_querymenu *qmenu) +static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu) { static const u32 mpeg_audio_encoding[] = { V4L2_MPEG_AUDIO_ENCODING_LAYER_2, @@ -632,11 +648,12 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h, V4L2_MPEG_AUDIO_AC3_BITRATE_384K, V4L2_CTRL_MENU_IDS_END }; + struct saa6752hs_state *h = to_state(sd); struct v4l2_queryctrl qctrl; int err; qctrl.id = qmenu->id; - err = saa6752hs_qctrl(h, &qctrl); + err = saa6752hs_queryctrl(sd, &qctrl); if (err) return err; switch (qmenu->id) { @@ -656,17 +673,16 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h, return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); } -static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) +static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes) { unsigned char buf[9], buf2[4]; - struct saa6752hs_state *h; + struct saa6752hs_state *h = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); unsigned size; u32 crc; unsigned char localPAT[256]; unsigned char localPMT[256]; - h = i2c_get_clientdata(client); - /* Set video format - must be done first as it resets other settings */ set_reg8(client, 0x41, h->video_format); @@ -762,7 +778,7 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) buf[3] = 0x82; buf[4] = 0xB0; buf[5] = buf2[0]; - switch(h->params.vi_aspect) { + switch (h->params.vi_aspect) { case V4L2_MPEG_VIDEO_ASPECT_16x9: buf[6] = buf2[1] | 0x40; break; @@ -770,7 +786,6 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) default: buf[6] = buf2[1] & 0xBF; break; - break; } buf[7] = buf2[2]; buf[8] = buf2[3]; @@ -779,81 +794,162 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) return 0; } -static int -saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set) { - struct saa6752hs_state *h = i2c_get_clientdata(client); - struct v4l2_ext_controls *ctrls = arg; + struct saa6752hs_state *h = to_state(sd); struct saa6752hs_mpeg_params params; - int err = 0; int i; - switch (cmd) { - case VIDIOC_INT_INIT: - /* apply settings and start encoder */ - saa6752hs_init(client, *(u32 *)arg); - break; - case VIDIOC_S_EXT_CTRLS: - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - /* fall through */ - case VIDIOC_TRY_EXT_CTRLS: - case VIDIOC_G_EXT_CTRLS: - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - params = h->params; - for (i = 0; i < ctrls->count; i++) { - err = handle_ctrl(h->has_ac3, ¶ms, ctrls->controls + i, cmd); - if (err) { - ctrls->error_idx = i; - return err; - } + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + params = h->params; + for (i = 0; i < ctrls->count; i++) { + int err = handle_ctrl(h->has_ac3, ¶ms, ctrls->controls + i, set); + + if (err) { + ctrls->error_idx = i; + return err; } - h->params = params; - break; - case VIDIOC_QUERYCTRL: - return saa6752hs_qctrl(h, arg); - case VIDIOC_QUERYMENU: - return saa6752hs_qmenu(h, arg); - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - - if (h->video_format == SAA6752HS_VF_UNKNOWN) - h->video_format = SAA6752HS_VF_D1; - f->fmt.pix.width = - v4l2_format_table[h->video_format].fmt.pix.width; - f->fmt.pix.height = - v4l2_format_table[h->video_format].fmt.pix.height; - break ; } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; + if (set) + h->params = params; + return 0; +} - saa6752hs_set_subsampling(client, f); - break; +static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) +{ + return saa6752hs_do_ext_ctrls(sd, ctrls, 1); +} + +static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) +{ + return saa6752hs_do_ext_ctrls(sd, ctrls, 0); +} + +static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) +{ + struct saa6752hs_state *h = to_state(sd); + int i; + + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + for (i = 0; i < ctrls->count; i++) { + int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i); + + if (err) { + ctrls->error_idx = i; + return err; + } } - case VIDIOC_S_STD: - h->standard = *((v4l2_std_id *) arg); - break; + return 0; +} - case VIDIOC_DBG_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, - arg, h->chip, h->revision); +static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct saa6752hs_state *h = to_state(sd); - default: - /* nothing */ - break; + if (h->video_format == SAA6752HS_VF_UNKNOWN) + h->video_format = SAA6752HS_VF_D1; + f->fmt.pix.width = + v4l2_format_table[h->video_format].fmt.pix.width; + f->fmt.pix.height = + v4l2_format_table[h->video_format].fmt.pix.height; + return 0; +} + +static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct saa6752hs_state *h = to_state(sd); + int dist_352, dist_480, dist_720; + + /* + FIXME: translate and round width/height into EMPRESS + subsample type: + + type | PAL | NTSC + --------------------------- + SIF | 352x288 | 352x240 + 1/2 D1 | 352x576 | 352x480 + 2/3 D1 | 480x576 | 480x480 + D1 | 720x576 | 720x480 + */ + + dist_352 = abs(f->fmt.pix.width - 352); + dist_480 = abs(f->fmt.pix.width - 480); + dist_720 = abs(f->fmt.pix.width - 720); + if (dist_720 < dist_480) { + f->fmt.pix.width = 720; + f->fmt.pix.height = 576; + h->video_format = SAA6752HS_VF_D1; + } else if (dist_480 < dist_352) { + f->fmt.pix.width = 480; + f->fmt.pix.height = 576; + h->video_format = SAA6752HS_VF_2_3_D1; + } else { + f->fmt.pix.width = 352; + if (abs(f->fmt.pix.height - 576) < + abs(f->fmt.pix.height - 288)) { + f->fmt.pix.height = 576; + h->video_format = SAA6752HS_VF_1_2_D1; + } else { + f->fmt.pix.height = 288; + h->video_format = SAA6752HS_VF_SIF; + } } + return 0; +} + +static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct saa6752hs_state *h = to_state(sd); + + h->standard = std; + return 0; +} - return err; +static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct saa6752hs_state *h = to_state(sd); + + return v4l2_chip_ident_i2c_client(client, + chip, h->chip, h->revision); } +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { + .g_chip_ident = saa6752hs_g_chip_ident, + .init = saa6752hs_init, + .queryctrl = saa6752hs_queryctrl, + .querymenu = saa6752hs_querymenu, + .g_ext_ctrls = saa6752hs_g_ext_ctrls, + .s_ext_ctrls = saa6752hs_s_ext_ctrls, + .try_ext_ctrls = saa6752hs_try_ext_ctrls, +}; + +static const struct v4l2_subdev_tuner_ops saa6752hs_tuner_ops = { + .s_std = saa6752hs_s_std, +}; + +static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { + .s_fmt = saa6752hs_s_fmt, + .g_fmt = saa6752hs_g_fmt, +}; + +static const struct v4l2_subdev_ops saa6752hs_ops = { + .core = &saa6752hs_core_ops, + .tuner = &saa6752hs_tuner_ops, + .video = &saa6752hs_video_ops, +}; + static int saa6752hs_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL); + struct v4l2_subdev *sd; u8 addr = 0x13; u8 data[12]; @@ -861,6 +957,8 @@ static int saa6752hs_probe(struct i2c_client *client, client->addr << 1, client->adapter->name); if (h == NULL) return -ENOMEM; + sd = &h->sd; + v4l2_i2c_subdev_init(sd, client, &saa6752hs_ops); i2c_master_send(client, &addr, 1); i2c_master_recv(client, data, sizeof(data)); @@ -874,14 +972,15 @@ static int saa6752hs_probe(struct i2c_client *client, } h->params = param_defaults; h->standard = 0; /* Assume 625 input lines */ - - i2c_set_clientdata(client, h); return 0; } static int saa6752hs_remove(struct i2c_client *client) { - kfree(i2c_get_clientdata(client)); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); return 0; } @@ -893,8 +992,6 @@ MODULE_DEVICE_TABLE(i2c, saa6752hs_id); static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "saa6752hs", - .driverid = I2C_DRIVERID_SAA6752HS, - .command = saa6752hs_command, .probe = saa6752hs_probe, .remove = saa6752hs_remove, .id_table = saa6752hs_id, diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index c750d3dd57d..8b0b64a8987 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -990,10 +990,10 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) if (!enable[devnum]) return -ENODEV; - card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, sizeof(snd_card_saa7134_t)); - - if (card == NULL) - return -ENOMEM; + err = snd_card_create(index[devnum], id[devnum], THIS_MODULE, + sizeof(snd_card_saa7134_t), &card); + if (err < 0) + return err; strcpy(card->driver, "SAA7134"); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index e2febcd6e52..a790a7246a6 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -31,6 +31,7 @@ #include <media/v4l2-common.h> #include <media/tveeprom.h> #include "tea5767.h" +#include "tda18271.h" /* commly used strings */ static char name_mute[] = "mute"; @@ -272,6 +273,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .empress_addr = 0x20, .inputs = {{ .name = name_comp1, @@ -408,6 +410,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .empress_addr = 0x20, .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x820000, .inputs = {{ @@ -818,6 +821,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .empress_addr = 0x20, .inputs = {{ .name = name_comp1, .vmux = 4, @@ -977,6 +981,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .empress_addr = 0x20, .inputs = {{ .name = name_comp1, .vmux = 1, @@ -1699,6 +1704,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .rds_addr = 0x10, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -2364,6 +2370,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .empress_addr = 0x21, .inputs = {{ .name = "Composite 0", .vmux = 0, @@ -3291,6 +3298,68 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200100, }, }, + [SAA7134_BOARD_HAUPPAUGE_HVR1120] = { + .name = "Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 3, + .mpeg = SAA7134_MPEG_DVB, + .ts_type = SAA7134_MPEG_TS_SERIAL, + .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x0000100, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0800100, /* GPIO 23 HI for FM */ + }, + }, + [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = { + .name = "Hauppauge WinTV-HVR1110r3", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 3, + .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x0000100, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0800100, /* GPIO 23 HI for FM */ + }, + }, [SAA7134_BOARD_CINERGY_HT_PCMCIA] = { .name = "Terratec Cinergy HT PCMCIA", .audio_clock = 0x00187de7, @@ -4070,6 +4139,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .empress_addr = 0x20, .tda9887_conf = TDA9887_PRESENT, .inputs = { { .name = name_tv, @@ -4106,6 +4176,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .empress_addr = 0x20, .tda9887_conf = TDA9887_PRESENT, .inputs = { { .name = name_tv, @@ -4143,6 +4214,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .empress_addr = 0x20, .tda9887_conf = TDA9887_PRESENT, .inputs = { { .name = name_tv, @@ -4323,13 +4395,13 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .tv = 1, }, { - .name = name_comp, - .vmux = 0, + .name = name_comp1, + .vmux = 3, .amux = LINE1, }, { .name = name_svideo, .vmux = 8, - .amux = LINE1, + .amux = LINE2, } }, .radio = { .name = name_radio, @@ -4421,8 +4493,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* no DVB support for now */ - /* .mpeg = SAA7134_MPEG_DVB, */ + .mpeg = SAA7134_MPEG_DVB, .inputs = { { .name = name_comp, .vmux = 1, @@ -4441,8 +4512,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* no DVB support for now */ - /* .mpeg = SAA7134_MPEG_DVB, */ + .mpeg = SAA7134_MPEG_DVB, .inputs = { { .name = name_comp, .vmux = 1, @@ -4611,7 +4681,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_type = TUNER_YMEC_TVF_5533MF, .radio_type = TUNER_TEA5767, .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, + .radio_addr = 0x60, .gpiomask = 0x80000700, .inputs = { { .name = name_tv, @@ -5405,6 +5475,36 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6706, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6707, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6708, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6709, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x670a, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x153b, .subdevice = 0x1172, .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, @@ -5821,8 +5921,8 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev, } -static int saa7134_tda8290_callback(struct saa7134_dev *dev, - int command, int arg) +static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev, + int command, int arg) { u8 sync_control; @@ -5848,6 +5948,65 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, return 0; } +static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev, + enum tda18271_mode mode) +{ + /* toggle AGC switch through GPIO 26 */ + switch (mode) { + case TDA18271_ANALOG: + saa7134_set_gpio(dev, 26, 0); + break; + case TDA18271_DIGITAL: + saa7134_set_gpio(dev, 26, 1); + break; + default: + return -EINVAL; + } + return 0; +} + +static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, + int command, int arg) +{ + int ret = 0; + + switch (command) { + case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */ + switch (dev->board) { + case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg); + break; + default: + break; + } + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int saa7134_tda8290_callback(struct saa7134_dev *dev, + int command, int arg) +{ + int ret; + + switch (dev->board) { + case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + /* tda8290 + tda18271 */ + ret = saa7134_tda8290_18271_callback(dev, command, arg); + break; + default: + /* tda8290 + tda827x */ + ret = saa7134_tda8290_827x_callback(dev, command, arg); + break; + } + return ret; +} + int saa7134_tuner_callback(void *priv, int component, int command, int arg) { struct saa7134_dev *dev = priv; @@ -5878,11 +6037,16 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) switch (tv.model) { case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */ case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ + case 67201: /* WinTV-HVR1120 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ + case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ + case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */ case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */ case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ + case 67651: /* WinTV-HVR1120 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ + case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ break; default: printk(KERN_WARNING "%s: warning: " @@ -6019,6 +6183,11 @@ int saa7134_board_init1(struct saa7134_dev *dev) msleep(10); break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: + saa7134_set_gpio(dev, 23, 0); + msleep(10); + saa7134_set_gpio(dev, 23, 1); + dev->has_remote = SAA7134_REMOTE_I2C; + break; case SAA7134_BOARD_AVERMEDIA_M103: saa7134_set_gpio(dev, 23, 0); msleep(10); @@ -6054,6 +6223,16 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00); break; + case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + /* GPIO 26 high for digital, low for analog */ + saa7134_set_gpio(dev, 26, 0); + msleep(1); + + saa7134_set_gpio(dev, 22, 0); + msleep(10); + saa7134_set_gpio(dev, 22, 1); + break; /* i2c remotes */ case SAA7134_BOARD_PINNACLE_PCTV_110i: case SAA7134_BOARD_PINNACLE_PCTV_310i: @@ -6079,15 +6258,15 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd); break; - case SAA7134_BOARD_AVERMEDIA_A700_PRO: case SAA7134_BOARD_AVERMEDIA_A700_HYBRID: - /* write windows gpio values */ - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100); printk("%s: %s: hybrid analog/dvb card\n" - "%s: Sorry, only analog s-video and composite input " + "%s: Sorry, of the analog inputs, only analog s-video and composite " "are supported for now.\n", dev->name, card(dev).name, dev->name); + case SAA7134_BOARD_AVERMEDIA_A700_PRO: + /* write windows gpio values */ + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100); break; } return 0; @@ -6109,7 +6288,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) tun_setup.mode_mask = T_RADIO; - saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + saa_call_all(dev, tuner, s_type_addr, &tun_setup); mode_mask &= ~T_RADIO; } @@ -6121,7 +6300,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) tun_setup.mode_mask = mode_mask; - saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + saa_call_all(dev, tuner, s_type_addr, &tun_setup); } if (dev->tda9887_conf) { @@ -6130,8 +6309,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) tda9887_cfg.tuner = TUNER_TDA9887; tda9887_cfg.priv = &dev->tda9887_conf; - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); + saa_call_all(dev, tuner, s_config, &tda9887_cfg); } if (dev->tuner_type == TUNER_XC2028) { @@ -6158,7 +6336,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) xc2028_cfg.tuner = TUNER_XC2028; xc2028_cfg.priv = &ctl; - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + saa_call_all(dev, tuner, s_config, &xc2028_cfg); } } @@ -6168,9 +6346,20 @@ int saa7134_board_init2(struct saa7134_dev *dev) unsigned char buf; int board; + /* Put here the code that enables the chips that are needed + for analog mode and doesn't depend on the tuner attachment. + It is also a good idea to get tuner type from eeprom, etc before + initializing tuner, since we can avoid loading tuner driver + on devices that has TUNER_ABSENT + */ switch (dev->board) { case SAA7134_BOARD_BMK_MPEX_NOTUNER: case SAA7134_BOARD_BMK_MPEX_TUNER: + /* Checks if the device has a tuner at 0x60 addr + If the device doesn't have a tuner, TUNER_ABSENT + will be used at tuner_type, avoiding loading tuner + without needing it + */ dev->i2c_client.addr = 0x60; board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0) ? SAA7134_BOARD_BMK_MPEX_NOTUNER @@ -6188,11 +6377,15 @@ int saa7134_board_init2(struct saa7134_dev *dev) u8 subaddr; u8 data[3]; int ret, tuner_t; - struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1}, {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}}; + subaddr= 0x14; tuner_t = 0; + + /* Retrieve device data from eeprom, checking for the + proper tuner_type. + */ ret = i2c_transfer(&dev->i2c_adap, msg, 2); if (ret != 2) { printk(KERN_ERR "EEPROM read failure\n"); @@ -6248,12 +6441,14 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->name, saa7134_boards[dev->board].name); break; } + /* break intentionally omitted */ 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 + /* 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)}; @@ -6274,21 +6469,15 @@ int saa7134_board_init2(struct saa7134_dev *dev) if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { dev->tuner_type = TUNER_PHILIPS_TDA8290; - saa7134_tuner_setup(dev); - 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; + break; } i2c_transfer(&dev->i2c_adap, &msg, 1); break; } - case SAA7134_BOARD_ASUSTeK_TVFM7135: - /* The card below is detected as card=53, but is different */ + case SAA7134_BOARD_ASUSTeK_TVFM7135: + /* The card below is detected as card=53, but is different */ if (dev->autodetected && (dev->eedata[0x27] == 0x03)) { dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG; printk(KERN_INFO "%s: P7131 analog only, using " @@ -6296,6 +6485,10 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->name, saa7134_boards[dev->board].name); } break; + case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + hauppauge_eeprom(dev, dev->eedata+0x80); + break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: hauppauge_eeprom(dev, dev->eedata+0x80); /* break intentionally omitted */ @@ -6351,22 +6544,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) i2c_transfer(&dev->i2c_adap, &msg, 1); break; } - case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI: - case SAA7134_BOARD_KWORLD_ATSC110: - { - /* 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, @@ -6375,9 +6552,9 @@ int saa7134_board_init2(struct saa7134_dev *dev) /* Don't do this if the board was specifically selected with an * insmod option or if we have the default configuration T200*/ - if(!dev->autodetected || (dev->eedata[0x41] == 0xd0)) + if (!dev->autodetected || (dev->eedata[0x41] == 0xd0)) break; - if(dev->eedata[0x41] == 0x02) { + if (dev->eedata[0x41] == 0x02) { /* Reconfigure board as T200A */ dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A; dev->tuner_type = saa7134_boards[dev->board].tuner_type; @@ -6390,6 +6567,58 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; } break; + case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI: + case SAA7134_BOARD_KWORLD_ATSC110: + { + struct i2c_msg msg = { .addr = 0x0a, .flags = 0 }; + int i; + static u8 buffer[][2] = { + { 0x10, 0x12 }, + { 0x13, 0x04 }, + { 0x16, 0x00 }, + { 0x14, 0x04 }, + { 0x17, 0x00 }, + }; + + for (i = 0; i < ARRAY_SIZE(buffer); i++) { + msg.buf = &buffer[i][0]; + msg.len = ARRAY_SIZE(buffer[0]); + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + printk(KERN_WARNING + "%s: Unable to enable tuner(%i).\n", + dev->name, i); + } + break; + } + } /* switch() */ + + /* initialize tuner */ + if (TUNER_ABSENT != dev->tuner_type) { + int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); + + /* Note: radio tuner address is always filled in, + so we do not need to probe for a radio tuner device. */ + if (dev->radio_type != UNSET) + v4l2_i2c_new_subdev(&dev->i2c_adap, + "tuner", "tuner", dev->radio_addr); + if (has_demod) + v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "tuner", + "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + if (dev->tuner_addr == ADDR_UNSET) { + enum v4l2_i2c_tuner_type type = + has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; + + v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "tuner", + "tuner", v4l2_i2c_tuner_addrs(type)); + } else { + v4l2_i2c_new_subdev(&dev->i2c_adap, + "tuner", "tuner", dev->tuner_addr); + } + } + + saa7134_tuner_setup(dev); + + switch (dev->board) { case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: { struct v4l2_priv_tun_config tea5767_cfg; @@ -6401,12 +6630,10 @@ int saa7134_board_init2(struct saa7134_dev *dev) 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); + saa_call_all(dev, tuner, s_config, &tea5767_cfg); break; } } /* switch() */ - saa7134_tuner_setup(dev); - return 0; } diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 99221d726ed..dafa0d88bed 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -54,13 +54,9 @@ static unsigned int gpio_tracking; module_param(gpio_tracking, int, 0644); MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]"); -static unsigned int alsa; +static unsigned int alsa = 1; module_param(alsa, int, 0644); -MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]"); - -static unsigned int oss; -module_param(oss, int, 0644); -MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]"); +MODULE_PARM_DESC(alsa,"enable/disable ALSA DMA sound [dmasound]"); static unsigned int latency = UNSET; module_param(latency, int, 0444); @@ -90,8 +86,10 @@ MODULE_PARM_DESC(radio_nr, "radio device number"); MODULE_PARM_DESC(tuner, "tuner type"); MODULE_PARM_DESC(card, "card type"); -static DEFINE_MUTEX(devlist_lock); +DEFINE_MUTEX(saa7134_devlist_lock); +EXPORT_SYMBOL(saa7134_devlist_lock); LIST_HEAD(saa7134_devlist); +EXPORT_SYMBOL(saa7134_devlist); static LIST_HEAD(mops_list); static unsigned int saa7134_devcount; @@ -156,10 +154,10 @@ static void request_module_async(struct work_struct *work){ request_module("saa7134-empress"); if (card_is_dvb(dev)) request_module("saa7134-dvb"); - if (alsa) - request_module("saa7134-alsa"); - if (oss) - request_module("saa7134-oss"); + if (alsa) { + if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130) + request_module("saa7134-alsa"); + } } static void request_submodules(struct saa7134_dev *dev) @@ -778,7 +776,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, return NULL; *vfd = *template; vfd->minor = -1; - vfd->parent = &dev->pci->dev; + vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", @@ -851,6 +849,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, if (NULL == dev) return -ENOMEM; + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); + if (err) + goto fail0; + /* pci init */ dev->pci = pci_dev; if (pci_enable_device(pci_dev)) { @@ -927,6 +929,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->autodetected = card[dev->nr] != dev->board; dev->tuner_type = saa7134_boards[dev->board].tuner_type; dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; + dev->radio_type = saa7134_boards[dev->board].radio_type; + dev->radio_addr = saa7134_boards[dev->board].radio_addr; dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[dev->nr]) dev->tuner_type = tuner[dev->nr]; @@ -971,23 +975,48 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, /* wait a bit, register i2c bus */ msleep(100); saa7134_i2c_register(dev); - - /* initialize hardware #2 */ - if (TUNER_ABSENT != dev->tuner_type) - request_module("tuner"); saa7134_board_init2(dev); saa7134_hwinit2(dev); /* load i2c helpers */ if (card_is_empress(dev)) { - request_module("saa6752hs"); + struct v4l2_subdev *sd = + v4l2_i2c_new_subdev(&dev->i2c_adap, + "saa6752hs", "saa6752hs", + saa7134_boards[dev->board].empress_addr); + + if (sd) + sd->grp_id = GRP_EMPRESS; + } + + if (saa7134_boards[dev->board].rds_addr) { + unsigned short addrs[2] = { 0, I2C_CLIENT_END }; + struct v4l2_subdev *sd; + + addrs[0] = saa7134_boards[dev->board].rds_addr; + sd = v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "saa6588", + "saa6588", addrs); + if (sd) + printk(KERN_INFO "%s: found RDS decoder\n", dev->name); } request_submodules(dev); v4l2_prio_init(&dev->prio); + mutex_lock(&saa7134_devlist_lock); + list_for_each_entry(mops, &mops_list, next) + mpeg_ops_attach(mops, dev); + list_add_tail(&dev->devlist, &saa7134_devlist); + mutex_unlock(&saa7134_devlist_lock); + + /* check for signal */ + saa7134_irq_video_signalchange(dev); + + if (TUNER_ABSENT != dev->tuner_type) + saa_call_all(dev, core, s_standby, 0); + /* register v4l devices */ if (saa7134_no_overlay > 0) printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name); @@ -1023,24 +1052,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, } /* everything worked */ - pci_set_drvdata(pci_dev,dev); saa7134_devcount++; - mutex_lock(&devlist_lock); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_attach(mops, dev); - list_add_tail(&dev->devlist,&saa7134_devlist); - mutex_unlock(&devlist_lock); - - /* check for signal */ - saa7134_irq_video_signalchange(dev); - - if (saa7134_dmasound_init && !dev->dmasound.priv_data) { + if (saa7134_dmasound_init && !dev->dmasound.priv_data) saa7134_dmasound_init(dev); - } - - if (TUNER_ABSENT != dev->tuner_type) - saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); return 0; @@ -1055,13 +1070,16 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, release_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); fail1: + v4l2_device_unregister(&dev->v4l2_dev); + fail0: kfree(dev); return err; } static void __devexit saa7134_finidev(struct pci_dev *pci_dev) { - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); struct saa7134_mpeg_ops *mops; /* Release DMA sound modules if present */ @@ -1088,11 +1106,11 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) saa7134_hwfini(dev); /* unregister */ - mutex_lock(&devlist_lock); + mutex_lock(&saa7134_devlist_lock); list_del(&dev->devlist); list_for_each_entry(mops, &mops_list, next) mpeg_ops_detach(mops, dev); - mutex_unlock(&devlist_lock); + mutex_unlock(&saa7134_devlist_lock); saa7134_devcount--; saa7134_i2c_unregister(dev); @@ -1113,7 +1131,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) release_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); - pci_set_drvdata(pci_dev, NULL); + + v4l2_device_unregister(&dev->v4l2_dev); /* free memory */ kfree(dev); @@ -1148,8 +1167,8 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev, static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) { - - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); /* disable overlay - apps should enable it explicitly on resume*/ dev->ovenable = 0; @@ -1185,7 +1204,8 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) static int saa7134_resume(struct pci_dev *pci_dev) { - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); unsigned long flags; pci_set_power_state(pci_dev, PCI_D0); @@ -1247,11 +1267,11 @@ int saa7134_ts_register(struct saa7134_mpeg_ops *ops) { struct saa7134_dev *dev; - mutex_lock(&devlist_lock); + mutex_lock(&saa7134_devlist_lock); list_for_each_entry(dev, &saa7134_devlist, devlist) mpeg_ops_attach(ops, dev); list_add_tail(&ops->next,&mops_list); - mutex_unlock(&devlist_lock); + mutex_unlock(&saa7134_devlist_lock); return 0; } @@ -1259,11 +1279,11 @@ void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops) { struct saa7134_dev *dev; - mutex_lock(&devlist_lock); + mutex_lock(&saa7134_devlist_lock); list_del(&ops->next); list_for_each_entry(dev, &saa7134_devlist, devlist) mpeg_ops_detach(ops, dev); - mutex_unlock(&devlist_lock); + mutex_unlock(&saa7134_devlist_lock); } EXPORT_SYMBOL(saa7134_ts_register); @@ -1307,8 +1327,6 @@ module_exit(saa7134_fini); /* ----------------------------------------------------------- */ EXPORT_SYMBOL(saa7134_set_gpio); -EXPORT_SYMBOL(saa7134_i2c_call_clients); -EXPORT_SYMBOL(saa7134_devlist); EXPORT_SYMBOL(saa7134_boards); /* ----------------- for the DMA sound modules --------------- */ diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index b5370b3e1a3..4eff1ca8593 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -48,9 +48,15 @@ #include "isl6405.h" #include "lnbp21.h" #include "tuner-simple.h" +#include "tda18271.h" +#include "lgdt3305.h" +#include "tda8290.h" #include "zl10353.h" +#include "zl10036.h" +#include "mt312.h" + MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); @@ -189,7 +195,7 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(&dev->i2c_adap, &msg, 1); - saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); + saa_call_all(dev, tuner, s_frequency, &f); msg.buf = on; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -950,6 +956,45 @@ static struct nxt200x_config kworldatsc110 = { .demod_address = 0x0a, }; +/* ------------------------------------------------------------------ */ + +static struct mt312_config avertv_a700_mt312 = { + .demod_address = 0x0e, + .voltage_inverted = 1, +}; + +static struct zl10036_config avertv_a700_tuner = { + .tuner_address = 0x60, +}; + +static struct lgdt3305_config hcw_lgdt3305_config = { + .i2c_addr = 0x0e, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .deny_i2c_rptr = 1, + .spectral_inversion = 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, +}; + +static struct tda18271_std_map hauppauge_tda18271_std_map = { + .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x58, }, + .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, + .if_lvl = 1, .rfagc_top = 0x58, }, +}; + +static struct tda18271_config hcw_tda18271_config = { + .std_map = &hauppauge_tda18271_std_map, + .gate = TDA18271_GATE_ANALOG, + .config = 3, +}; + +static struct tda829x_config tda829x_no_probe = { + .probe_tuner = TDA829X_DONT_PROBE, +}; + /* ================================================================== * Core code */ @@ -1076,6 +1121,19 @@ static int dvb_init(struct saa7134_dev *dev) &tda827x_cfg_1) < 0) goto dettach_frontend; break; + case SAA7134_BOARD_HAUPPAUGE_HVR1120: + fe0->dvb.frontend = dvb_attach(lgdt3305_attach, + &hcw_lgdt3305_config, + &dev->i2c_adap); + if (fe0->dvb.frontend) { + dvb_attach(tda829x_attach, fe0->dvb.frontend, + &dev->i2c_adap, 0x4b, + &tda829x_no_probe); + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_adap, + &hcw_tda18271_config); + } + break; case SAA7134_BOARD_ASUSTeK_P7131_DUAL: if (configure_tda827x_fe(dev, &asus_p7131_dual_config, &tda827x_cfg_0) < 0) @@ -1376,6 +1434,19 @@ static int dvb_init(struct saa7134_dev *dev) TUNER_PHILIPS_FMD1216ME_MK3); } break; + case SAA7134_BOARD_AVERMEDIA_A700_PRO: + case SAA7134_BOARD_AVERMEDIA_A700_HYBRID: + /* Zarlink ZL10313 */ + fe0->dvb.frontend = dvb_attach(mt312_attach, + &avertv_a700_mt312, &dev->i2c_adap); + if (fe0->dvb.frontend) { + if (dvb_attach(zl10036_attach, fe0->dvb.frontend, + &avertv_a700_tuner, &dev->i2c_adap) == NULL) { + wprintk("%s: No zl10036 found!\n", + __func__); + } + } + break; default: wprintk("Huh? unknown DVB card?\n"); break; @@ -1449,7 +1520,7 @@ static int dvb_fini(struct saa7134_dev *dev) tda9887_cfg.priv = &on; /* otherwise we don't detect the tuner on next insmod */ - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg); + saa_call_all(dev, tuner, s_config, &tda9887_cfg); } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) { if ((dev->eedata[2] == 0x07) && use_frontend) { /* turn off the 2nd lnb supply */ diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index c9d8beb87a6..9db3472667e 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -76,7 +76,7 @@ static int ts_init_encoder(struct saa7134_dev* dev) break; } ts_reset_encoder(dev); - saa7134_i2c_call_clients(dev, VIDIOC_INT_INIT, &leading_null_bytes); + saa_call_all(dev, core, init, leading_null_bytes); dev->empress_started = 1; return 0; } @@ -234,7 +234,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, { struct saa7134_dev *dev = file->private_data; - saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f); + saa_call_all(dev, video, g_fmt, f); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -247,7 +247,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, { struct saa7134_dev *dev = file->private_data; - saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f); + saa_call_all(dev, video, s_fmt, f); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -317,7 +317,7 @@ static int empress_s_ext_ctrls(struct file *file, void *priv, if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - err = saa7134_i2c_call_saa6752(dev, VIDIOC_S_EXT_CTRLS, ctrls); + err = saa_call_empress(dev, core, s_ext_ctrls, ctrls); ts_init_encoder(dev); return err; @@ -330,7 +330,7 @@ static int empress_g_ext_ctrls(struct file *file, void *priv, if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls); + return saa_call_empress(dev, core, g_ext_ctrls, ctrls); } static int empress_g_ctrl(struct file *file, void *priv, @@ -352,6 +352,7 @@ static int empress_s_ctrl(struct file *file, void *priv, static int empress_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { + /* Must be sorted from low to high control ID! */ static const u32 user_ctrls[] = { V4L2_CID_USER_CLASS, V4L2_CID_BRIGHTNESS, @@ -364,6 +365,7 @@ static int empress_queryctrl(struct file *file, void *priv, 0 }; + /* Must be sorted from low to high control ID! */ static const u32 mpeg_ctrls[] = { V4L2_CID_MPEG_CLASS, V4L2_CID_MPEG_STREAM_TYPE, @@ -388,10 +390,10 @@ static int empress_queryctrl(struct file *file, void *priv, if (c->id == 0) return -EINVAL; if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS) - return v4l2_ctrl_query_fill_std(c); + return v4l2_ctrl_query_fill(c, 0, 0, 0, 0); if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) return saa7134_queryctrl(file, priv, c); - return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYCTRL, c); + return saa_call_empress(dev, core, queryctrl, c); } static int empress_querymenu(struct file *file, void *priv, @@ -401,7 +403,7 @@ static int empress_querymenu(struct file *file, void *priv, if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c); + return saa_call_empress(dev, core, querymenu, c); } static int empress_g_chip_ident(struct file *file, void *fh, @@ -411,14 +413,11 @@ static int empress_g_chip_ident(struct file *file, void *fh, chip->ident = V4L2_IDENT_NONE; chip->revision = 0; - if (dev->mpeg_i2c_client == NULL) - return -EINVAL; if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER && !strcmp(chip->match.name, "saa6752hs")) - return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip); - if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR && - chip->match.addr == dev->mpeg_i2c_client->addr) - return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip); + return saa_call_empress(dev, core, g_chip_ident, chip); + if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR) + return saa_call_empress(dev, core, g_chip_ident, chip); return -EINVAL; } diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 20c1b33caf7..f3e285aa2fb 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -255,7 +255,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, addr = msgs[i].addr << 1; if (msgs[i].flags & I2C_M_RD) addr |= 1; - if (i > 0 && msgs[i].flags & I2C_M_RD) { + if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) { /* workaround for a saa7134 i2c bug * needed to talk to the mt352 demux * thanks to pinnacle for the hint */ @@ -327,8 +327,6 @@ static int attach_inform(struct i2c_client *client) d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); - if (client->addr == 0x20 && client->driver && client->driver->command) - dev->mpeg_i2c_client = client; /* Am I an i2c remote control? */ @@ -357,7 +355,6 @@ static struct i2c_algorithm saa7134_algo = { static struct i2c_adapter saa7134_adap_template = { .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, .name = "saa7134", .id = I2C_HW_SAA7134, .algo = &saa7134_algo, @@ -421,29 +418,13 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -void saa7134_i2c_call_clients(struct saa7134_dev *dev, - unsigned int cmd, void *arg) -{ - BUG_ON(NULL == dev->i2c_adap.algo_data); - i2c_clients_command(&dev->i2c_adap, cmd, arg); -} - -int saa7134_i2c_call_saa6752(struct saa7134_dev *dev, - unsigned int cmd, void *arg) -{ - if (dev->mpeg_i2c_client == NULL) - return -EINVAL; - return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client, - cmd, arg); -} -EXPORT_SYMBOL_GPL(saa7134_i2c_call_saa6752); - int saa7134_i2c_register(struct saa7134_dev *dev) { dev->i2c_adap = saa7134_adap_template; dev->i2c_adap.dev.parent = &dev->pci->dev; strcpy(dev->i2c_adap.name,dev->name); dev->i2c_adap.algo_data = dev; + i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); i2c_add_adapter(&dev->i2c_adap); dev->i2c_client = saa7134_client_template; diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index ef55a59f0cd..cc8b923afbc 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -79,8 +79,19 @@ static int buffer_activate(struct saa7134_dev *dev, saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* Start TS stream */ - saa_writeb(SAA7134_TS_SERIAL0, 0x40); - saa_writeb(SAA7134_TS_PARALLEL, 0xEC); + switch (saa7134_boards[dev->board].ts_type) { + case SAA7134_MPEG_TS_PARALLEL: + saa_writeb(SAA7134_TS_SERIAL0, 0x40); + saa_writeb(SAA7134_TS_PARALLEL, 0xec); + break; + case SAA7134_MPEG_TS_SERIAL: + saa_writeb(SAA7134_TS_SERIAL0, 0xd8); + saa_writeb(SAA7134_TS_PARALLEL, 0x6c); + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc); + saa_writeb(SAA7134_TS_SERIAL1, 0x02); + break; + } + dev->ts_state = SAA7134_TS_STARTED; } diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index a1f7e351f57..404f70eeb35 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -30,11 +30,7 @@ #include "saa7134-reg.h" #include "saa7134.h" #include <media/v4l2-common.h> - -#ifdef CONFIG_VIDEO_V4L1_COMPAT -/* Include V4L1 specific functions. Should be removed soon */ -#include <linux/videodev.h> -#endif +#include <media/rds.h> /* ------------------------------------------------------------------ */ @@ -452,6 +448,7 @@ static const struct v4l2_queryctrl video_ctrls[] = { .name = "y offset odd field", .minimum = 0, .maximum = 128, + .step = 1, .default_value = 0, .type = V4L2_CTRL_TYPE_INTEGER, },{ @@ -459,6 +456,7 @@ static const struct v4l2_queryctrl video_ctrls[] = { .name = "y offset even field", .minimum = 0, .maximum = 128, + .step = 1, .default_value = 0, .type = V4L2_CTRL_TYPE_INTEGER, },{ @@ -627,10 +625,10 @@ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev) saa7134_set_decoder(dev); if (card_in(dev, dev->ctl_input).tv) - saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); + saa_call_all(dev, tuner, s_std, dev->tvnorm->id); /* Set the correct norm for the saa6752hs. This function does nothing if there is no saa6752hs. */ - saa7134_i2c_call_saa6752(dev, VIDIOC_S_STD, &dev->tvnorm->id); + saa_call_empress(dev, tuner, s_std, dev->tvnorm->id); } static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) @@ -1266,8 +1264,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str else dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); + saa_call_all(dev, tuner, s_config, &tda9887_cfg); } break; } @@ -1334,7 +1331,7 @@ static int video_open(struct file *file) enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; - lock_kernel(); + mutex_lock(&saa7134_devlist_lock); list_for_each_entry(dev, &saa7134_devlist, devlist) { if (dev->video_dev && (dev->video_dev->minor == minor)) goto found; @@ -1347,19 +1344,20 @@ static int video_open(struct file *file) goto found; } } - unlock_kernel(); + mutex_unlock(&saa7134_devlist_lock); return -ENODEV; - found: + +found: + mutex_unlock(&saa7134_devlist_lock); dprintk("open minor=%d radio=%d type=%s\n",minor,radio, v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) { - unlock_kernel(); + if (NULL == fh) return -ENOMEM; - } + file->private_data = fh; fh->dev = dev; fh->radio = radio; @@ -1387,12 +1385,11 @@ static int video_open(struct file *file) if (fh->radio) { /* switch to radio mode */ saa7134_tvaudio_setinput(dev,&card(dev).radio); - saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL); + saa_call_all(dev, tuner, s_radio); } else { /* switch to video/vbi mode */ video_mux(dev,dev->ctl_input); } - unlock_kernel(); return 0; } @@ -1466,6 +1463,7 @@ static int video_release(struct file *file) { struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; + struct rds_command cmd; unsigned long flags; /* turn off overlay */ @@ -1498,7 +1496,9 @@ static int video_release(struct file *file) saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); - saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); + saa_call_all(dev, core, s_standby, 0); + if (fh->radio) + saa_call_all(dev, core, ioctl, RDS_CMD_CLOSE, &cmd); /* free stuff */ videobuf_mmap_free(&fh->cap); @@ -1519,6 +1519,37 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma) return videobuf_mmap_mapper(saa7134_queue(fh), vma); } +static ssize_t radio_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + struct rds_command cmd; + + cmd.block_count = count/3; + cmd.buffer = data; + cmd.instance = file; + cmd.result = -ENODEV; + + saa_call_all(dev, core, ioctl, RDS_CMD_READ, &cmd); + + return cmd.result; +} + +static unsigned int radio_poll(struct file *file, poll_table *wait) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + struct rds_command cmd; + + cmd.instance = file; + cmd.event_list = wait; + cmd.result = -ENODEV; + saa_call_all(dev, core, ioctl, RDS_CMD_POLL, &cmd); + + return cmd.result; +} + /* ------------------------------------------------------------------ */ static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, @@ -2041,7 +2072,7 @@ static int saa7134_s_frequency(struct file *file, void *priv, mutex_lock(&dev->lock); dev->ctl_freq = f->frequency; - saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); + saa_call_all(dev, tuner, s_frequency, f); saa7134_tvaudio_do_scan(dev); mutex_unlock(&dev->lock); @@ -2299,7 +2330,7 @@ static int radio_g_tuner(struct file *file, void *priv, strcpy(t->name, "Radio"); t->type = V4L2_TUNER_RADIO; - saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + saa_call_all(dev, tuner, g_tuner, t); if (dev->input->amux == TV) { t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); t->rxsubchans = (saa_readb(0x529) & 0x08) ? @@ -2316,7 +2347,7 @@ static int radio_s_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + saa_call_all(dev, tuner, s_tuner, t); return 0; } @@ -2443,8 +2474,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { static const struct v4l2_file_operations radio_fops = { .owner = THIS_MODULE, .open = video_open, + .read = radio_read, .release = video_release, .ioctl = video_ioctl2, + .poll = radio_poll, }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 14ee265f337..a2dd326de5b 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -35,6 +35,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> #include <media/tuner.h> #include <media/ir-common.h> #include <media/ir-kbd-i2c.h> @@ -277,6 +278,8 @@ struct saa7134_format { #define SAA7134_BOARD_ASUSTeK_TIGER 152 #define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153 #define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154 +#define SAA7134_BOARD_HAUPPAUGE_HVR1120 155 +#define SAA7134_BOARD_HAUPPAUGE_HVR1110R3 156 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 @@ -309,6 +312,11 @@ enum saa7134_mpeg_type { SAA7134_MPEG_DVB, }; +enum saa7134_mpeg_ts_type { + SAA7134_MPEG_TS_PARALLEL = 0, + SAA7134_MPEG_TS_SERIAL, +}; + struct saa7134_board { char *name; unsigned int audio_clock; @@ -324,6 +332,8 @@ struct saa7134_board { unsigned int radio_type; unsigned char tuner_addr; unsigned char radio_addr; + unsigned char empress_addr; + unsigned char rds_addr; unsigned int tda9887_conf; unsigned int tuner_config; @@ -331,6 +341,7 @@ struct saa7134_board { /* peripheral I/O */ enum saa7134_video_out video_out; enum saa7134_mpeg_type mpeg; + enum saa7134_mpeg_ts_type ts_type; unsigned int vid_port_opts; }; @@ -445,7 +456,6 @@ struct saa7134_dmasound { unsigned int bufsize; struct saa7134_pgtable pt; struct videobuf_dmabuf dma; - wait_queue_head_t wq; unsigned int dma_blk; unsigned int read_offset; unsigned int read_count; @@ -482,6 +492,7 @@ struct saa7134_dev { struct mutex lock; spinlock_t slock; struct v4l2_prio_state prio; + struct v4l2_device v4l2_dev; /* workstruct for loading modules */ struct work_struct request_module_wk; @@ -572,7 +583,6 @@ struct saa7134_dev { enum saa7134_ts_status ts_state; unsigned int buff_cnt; struct saa7134_mpeg_ops *mops; - struct i2c_client *mpeg_i2c_client; /* SAA7134_MPEG_EMPRESS only */ struct video_device *empress_dev; @@ -588,6 +598,7 @@ struct saa7134_dev { int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg); #endif + void (*gate_ctrl)(struct saa7134_dev *dev, int open); }; /* ----------------------------------------------------------- */ @@ -616,10 +627,31 @@ struct saa7134_dev { V4L2_STD_NTSC | V4L2_STD_PAL_M | \ V4L2_STD_PAL_60) +#define GRP_EMPRESS (1) +#define saa_call_all(dev, o, f, args...) do { \ + if (dev->gate_ctrl) \ + dev->gate_ctrl(dev, 1); \ + v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \ + if (dev->gate_ctrl) \ + dev->gate_ctrl(dev, 0); \ +} while (0) + +#define saa_call_empress(dev, o, f, args...) ({ \ + long _rc; \ + if (dev->gate_ctrl) \ + dev->gate_ctrl(dev, 1); \ + _rc = v4l2_device_call_until_err(&(dev)->v4l2_dev, \ + GRP_EMPRESS, o, f , ##args); \ + if (dev->gate_ctrl) \ + dev->gate_ctrl(dev, 0); \ + _rc; \ +}) + /* ----------------------------------------------------------- */ /* saa7134-core.c */ extern struct list_head saa7134_devlist; +extern struct mutex saa7134_devlist_lock; extern int saa7134_no_overlay; void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); @@ -668,10 +700,6 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg); int saa7134_i2c_register(struct saa7134_dev *dev); int saa7134_i2c_unregister(struct saa7134_dev *dev); -void saa7134_i2c_call_clients(struct saa7134_dev *dev, - unsigned int cmd, void *arg); -int saa7134_i2c_call_saa6752(struct saa7134_dev *dev, - unsigned int cmd, void *arg); /* ----------------------------------------------------------- */ |