diff options
122 files changed, 3390 insertions, 1606 deletions
diff --git a/linux/Documentation/video4linux/CARDLIST.cx23885 b/linux/Documentation/video4linux/CARDLIST.cx23885 index 91aa3c0f0..948e43610 100644 --- a/linux/Documentation/video4linux/CARDLIST.cx23885 +++ b/linux/Documentation/video4linux/CARDLIST.cx23885 @@ -16,3 +16,7 @@ 15 -> TeVii S470 [d470:9022] 16 -> DVBWorld DVB-S2 2005 [0001:2005] 17 -> NetUP Dual DVB-S2 CI [1b55:2a2c] + 18 -> Hauppauge WinTV-HVR1270 [0070:2211] + 19 -> Hauppauge WinTV-HVR1275 [0070:2215] + 20 -> Hauppauge WinTV-HVR1255 [0070:2251] + 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295] diff --git a/linux/Documentation/video4linux/CARDLIST.em28xx b/linux/Documentation/video4linux/CARDLIST.em28xx index bf58d957e..20aa65a70 100644 --- a/linux/Documentation/video4linux/CARDLIST.em28xx +++ b/linux/Documentation/video4linux/CARDLIST.em28xx @@ -62,3 +62,5 @@ 64 -> Easy Cap Capture DC-60 (em2860) 65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515] 66 -> Empire dual TV (em2880) + 67 -> Terratec Grabby (em2860) [0ccd:0096] + 68 -> Terratec AV350 (em2860) [0ccd:0084] diff --git a/linux/Documentation/video4linux/CARDLIST.saa7134 b/linux/Documentation/video4linux/CARDLIST.saa7134 index 112ff4f4f..e56934e50 100644 --- a/linux/Documentation/video4linux/CARDLIST.saa7134 +++ b/linux/Documentation/video4linux/CARDLIST.saa7134 @@ -154,7 +154,7 @@ 153 -> Kworld Plus TV Analog Lite PCI [17de:7128] 154 -> Avermedia AVerTV GO 007 FM Plus [1461:f31d] 155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid [0070:6706,0070:6708] -156 -> Hauppauge WinTV-HVR1110r3 [0070:6707,0070:6709,0070:670a] +156 -> Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid [0070:6707,0070:6709,0070:670a] 157 -> Avermedia AVerTV Studio 507UA [1461:a11b] 158 -> AVerMedia Cardbus TV/Radio (E501R) [1461:b7e9] 159 -> Beholder BeholdTV 505 RDS [0000:505B] diff --git a/linux/Documentation/video4linux/CARDLIST.tuner b/linux/Documentation/video4linux/CARDLIST.tuner index 691d2f37d..22c1c5597 100644 --- a/linux/Documentation/video4linux/CARDLIST.tuner +++ b/linux/Documentation/video4linux/CARDLIST.tuner @@ -76,3 +76,4 @@ tuner=75 - Philips TEA5761 FM Radio tuner=76 - Xceive 5000 tuner tuner=77 - TCL tuner MF02GIP-5N-E tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner +tuner=79 - Philips PAL/SECAM multi (FM1216 MK5) diff --git a/linux/drivers/media/common/tuners/tuner-types.c b/linux/drivers/media/common/tuners/tuner-types.c index d83df3604..43afd30b0 100644 --- a/linux/drivers/media/common/tuners/tuner-types.c +++ b/linux/drivers/media/common/tuners/tuner-types.c @@ -579,6 +579,31 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = { }, }; +/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */ + +static struct tuner_range tuner_fm1216mk5_pal_ranges[] = { + { 16 * 158.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 441.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 864.00 , 0xce, 0x04, }, +}; + +static struct tuner_params tuner_fm1216mk5_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_fm1216mk5_pal_ranges, + .count = ARRAY_SIZE(tuner_fm1216mk5_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[] = { @@ -1695,6 +1720,11 @@ struct tunertype tuners[] = { .initdata = tua603x_agc112, .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, }, + [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */ + .name = "Philips PAL/SECAM multi (FM1216 MK5)", + .params = tuner_fm1216mk5_params, + .count = ARRAY_SIZE(tuner_fm1216mk5_params), + }, }; EXPORT_SYMBOL(tuners); diff --git a/linux/drivers/media/common/tuners/tuner-xc2028.c b/linux/drivers/media/common/tuners/tuner-xc2028.c index bd010379b..cb5b577fa 100644 --- a/linux/drivers/media/common/tuners/tuner-xc2028.c +++ b/linux/drivers/media/common/tuners/tuner-xc2028.c @@ -34,7 +34,7 @@ MODULE_PARM_DESC(debug, "enable verbose debug messages"); static int no_poweroff; module_param(no_poweroff, int, 0644); -MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n" +MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" "1 keep device energized and with tuner ready all the times.\n" " Faster, but consumes more power and keeps the device hotter\n"); @@ -276,7 +276,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) fname = firmware_name; tuner_dbg("Reading firmware %s\n", fname); - rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev); + rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); if (rc < 0) { if (rc == -ENOENT) tuner_err("Error: firmware %s not found.\n", diff --git a/linux/drivers/media/common/tuners/xc5000.c b/linux/drivers/media/common/tuners/xc5000.c index 39c415df0..6626d19b3 100644 --- a/linux/drivers/media/common/tuners/xc5000.c +++ b/linux/drivers/media/common/tuners/xc5000.c @@ -3,6 +3,7 @@ * * Copyright (c) 2007 Xceive Corporation * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> + * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.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 @@ -36,14 +37,20 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); +static int no_poweroff; +module_param(no_poweroff, int, 0644); +MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" + "\t\t1 keep device energized and with tuner ready all the times.\n" + "\t\tFaster, but consumes more power and keeps the device hotter"); + static DEFINE_MUTEX(xc5000_list_mutex); static LIST_HEAD(hybrid_tuner_instance_list); #define dprintk(level, fmt, arg...) if (debug >= level) \ printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) -#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw" -#define XC5000_DEFAULT_FIRMWARE_SIZE 12332 +#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" +#define XC5000_DEFAULT_FIRMWARE_SIZE 12401 struct xc5000_priv { struct tuner_i2c_props i2c_props; @@ -83,11 +90,11 @@ struct xc5000_priv { #define XREG_D_CODE 0x04 #define XREG_IF_OUT 0x05 #define XREG_SEEK_MODE 0x07 -#define XREG_POWER_DOWN 0x0A +#define XREG_POWER_DOWN 0x0A /* Obsolete */ #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ #define XREG_SMOOTHEDCVBS 0x0E #define XREG_XTALFREQ 0x0F -#define XREG_FINERFFREQ 0x10 +#define XREG_FINERFREQ 0x10 #define XREG_DDIMODE 0x11 #define XREG_ADC_ENV 0x00 @@ -100,6 +107,7 @@ struct xc5000_priv { #define XREG_VERSION 0x07 #define XREG_PRODUCT_ID 0x08 #define XREG_BUSY 0x09 +#define XREG_BUILD 0x0D /* Basic firmware description. This will remain with @@ -191,27 +199,36 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { {"FM Radio-INPUT1", 0x0208, 0x9002} }; -static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); -static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len); -static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len); -static void xc5000_TunerReset(struct dvb_frontend *fe); +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); +static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); +static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); +static int xc5000_TunerReset(struct dvb_frontend *fe); static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) { - return xc5000_writeregs(priv, buf, len) - ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS; + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); + return XC_RESULT_I2C_WRITE_FAILURE; + } + return XC_RESULT_SUCCESS; } +/* This routine is never used because the only time we read data from the + i2c bus is when we read registers, and we want that to be an atomic i2c + transaction in case we are on a multi-master bus */ static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) { - return xc5000_readregs(priv, buf, len) - ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS; -} + struct i2c_msg msg = { .addr = priv->i2c_props.addr, + .flags = I2C_M_RD, .buf = buf, .len = len }; -static int xc_reset(struct dvb_frontend *fe) -{ - xc5000_TunerReset(fe); - return XC_RESULT_SUCCESS; + if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { + printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); + return -EREMOTEIO; + } + return 0; } static void xc_wait(int wait_ms) @@ -219,7 +236,7 @@ static void xc_wait(int wait_ms) msleep(wait_ms); } -static void xc5000_TunerReset(struct dvb_frontend *fe) +static int xc5000_TunerReset(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; int ret; @@ -232,16 +249,21 @@ static void xc5000_TunerReset(struct dvb_frontend *fe) priv->i2c_props.adap->algo_data, DVB_FRONTEND_COMPONENT_TUNER, XC5000_TUNER_RESET, 0); - if (ret) + if (ret) { printk(KERN_ERR "xc5000: reset failed\n"); - } else + return XC_RESULT_RESET_FAILURE; + } + } else { printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); + return XC_RESULT_RESET_FAILURE; + } + return XC_RESULT_SUCCESS; } static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) { u8 buf[4]; - int WatchDogTimer = 5; + int WatchDogTimer = 100; int result; buf[0] = (regAddr >> 8) & 0xFF; @@ -263,7 +285,7 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) /* busy flag cleared */ break; } else { - xc_wait(100); /* wait 5 ms */ + xc_wait(5); /* wait 5 ms */ WatchDogTimer--; } } @@ -276,25 +298,6 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) return result; } -static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData) -{ - u8 buf[2]; - int result; - - buf[0] = (regAddr >> 8) & 0xFF; - buf[1] = regAddr & 0xFF; - result = xc_send_i2c_data(priv, buf, 2); - if (result != XC_RESULT_SUCCESS) - return result; - - result = xc_read_i2c_data(priv, buf, 2); - if (result != XC_RESULT_SUCCESS) - return result; - - *i2cData = buf[0] * 256 + buf[1]; - return result; -} - static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) { struct xc5000_priv *priv = fe->tuner_priv; @@ -309,7 +312,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; if (len == 0x0000) { /* RESET command */ - result = xc_reset(fe); + result = xc5000_TunerReset(fe); index += 2; if (result != XC_RESULT_SUCCESS) return result; @@ -371,15 +374,6 @@ static int xc_SetTVStandard(struct xc5000_priv *priv, return ret; } -static int xc_shutdown(struct xc5000_priv *priv) -{ - return XC_RESULT_SUCCESS; - /* Fixme: cannot bring tuner back alive once shutdown - * without reloading the driver modules. - * return xc_write_reg(priv, XREG_POWER_DOWN, 0); - */ -} - static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) { dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, @@ -408,22 +402,14 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) freq_code = (u16)(freq_hz / 15625); - return xc_write_reg(priv, XREG_RF_FREQ, freq_code); + /* Starting in firmware version 1.1.44, Xceive recommends using the + FINERFREQ for all normal tuning (the doc indicates reg 0x03 should + only be used for fast scanning for channel lock) */ + return xc_write_reg(priv, XREG_FINERFREQ, freq_code); } #if 0 /* We'll probably need these for analog support */ -static int xc_FineTune_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) -{ - u16 freq_code = (u16)(freq_hz / 15625); - - if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || - (freq_hz < xc5000_tuner_ops.info.frequency_min)) - return XC_RESULT_OUT_OF_RANGE; - - return xc_write_reg(priv, XREG_FINERFFREQ, freq_code); -} - static int xc_set_Xtal_frequency(struct xc5000_priv *priv, u32 xtalFreqInKHz) { u16 xtalRatio = (32000 * 0x8000)/xtalFreqInKHz; @@ -443,7 +429,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) { - return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope); + return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); } static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) @@ -452,8 +438,8 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) u16 regData; u32 tmp; - result = xc_read_reg(priv, XREG_FREQ_ERROR, ®Data); - if (result) + result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); + if (result != XC_RESULT_SUCCESS) return result; tmp = (u32)regData; @@ -463,7 +449,7 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) { - return xc_read_reg(priv, XREG_LOCK, lock_status); + return xc5000_readreg(priv, XREG_LOCK, lock_status); } static int xc_get_version(struct xc5000_priv *priv, @@ -473,8 +459,8 @@ static int xc_get_version(struct xc5000_priv *priv, u16 data; int result; - result = xc_read_reg(priv, XREG_VERSION, &data); - if (result) + result = xc5000_readreg(priv, XREG_VERSION, &data); + if (result != XC_RESULT_SUCCESS) return result; (*hw_majorversion) = (data >> 12) & 0x0F; @@ -485,13 +471,18 @@ static int xc_get_version(struct xc5000_priv *priv, return 0; } +static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) +{ + return xc5000_readreg(priv, XREG_BUILD, buildrev); +} + static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) { u16 regData; int result; - result = xc_read_reg(priv, XREG_HSYNC_FREQ, ®Data); - if (result) + result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); + if (result != XC_RESULT_SUCCESS) return result; (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; @@ -500,12 +491,12 @@ static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) { - return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines); + return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); } static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) { - return xc_read_reg(priv, XREG_QUALITY, quality); + return xc5000_readreg(priv, XREG_QUALITY, quality); } static u16 WaitForLock(struct xc5000_priv *priv) @@ -523,7 +514,9 @@ static u16 WaitForLock(struct xc5000_priv *priv) return lockState; } -static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) +#define XC_TUNE_ANALOG 0 +#define XC_TUNE_DIGITAL 1 +static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) { int found = 0; @@ -532,8 +525,10 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) return 0; - if (WaitForLock(priv) == 1) - found = 1; + if (mode == XC_TUNE_ANALOG) { + if (WaitForLock(priv) == 1) + found = 1; + } return found; } @@ -555,32 +550,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) } *val = (bval[0] << 8) | bval[1]; - return 0; -} - -static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = 0, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", - (int)len); - return -EREMOTEIO; - } - return 0; -} - -static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = priv->i2c_props.addr, - .flags = I2C_M_RD, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { - printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len); - return -EREMOTEIO; - } - return 0; + return XC_RESULT_SUCCESS; } static int xc5000_fwupload(struct dvb_frontend *fe) @@ -594,13 +564,13 @@ static int xc5000_fwupload(struct dvb_frontend *fe) XC5000_DEFAULT_FIRMWARE); ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, - &priv->i2c_props.adap->dev); + priv->i2c_props.adap->dev.parent); if (ret) { printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); ret = XC_RESULT_RESET_FAILURE; goto out; } else { - printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n", + printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", fw->size); ret = XC_RESULT_SUCCESS; } @@ -609,8 +579,9 @@ static int xc5000_fwupload(struct dvb_frontend *fe) printk(KERN_ERR "xc5000: firmware incorrect size\n"); ret = XC_RESULT_RESET_FAILURE; } else { - printk(KERN_INFO "xc5000: firmware upload\n"); + printk(KERN_INFO "xc5000: firmware uploading...\n"); ret = xc_load_i2c_sequence(fe, fw->data); + printk(KERN_INFO "xc5000: firmware upload complete...\n"); } out: @@ -628,6 +599,7 @@ static void xc_debug_dump(struct xc5000_priv *priv) u16 quality; u8 hw_majorversion = 0, hw_minorversion = 0; u8 fw_majorversion = 0, fw_minorversion = 0; + u16 fw_buildversion = 0; /* Wait for stats to stabilize. * Frame Lines needs two frame times after initial lock @@ -647,9 +619,10 @@ static void xc_debug_dump(struct xc5000_priv *priv) xc_get_version(priv, &hw_majorversion, &hw_minorversion, &fw_majorversion, &fw_minorversion); - dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", + xc_get_buildversion(priv, &fw_buildversion); + dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n", hw_majorversion, hw_minorversion, - fw_majorversion, fw_minorversion); + fw_majorversion, fw_minorversion, fw_buildversion); xc_get_hsync_freq(priv, &hsync_freq_hz); dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); @@ -667,27 +640,57 @@ static int xc5000_set_params(struct dvb_frontend *fe, struct xc5000_priv *priv = fe->tuner_priv; int ret; + if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) + xc_load_fw_and_init_tuner(fe); + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - dprintk(1, "%s() VSB modulation\n", __func__); + if (fe->ops.info.type == FE_ATSC) { + dprintk(1, "%s() ATSC\n", __func__); + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + break; + default: + return -EINVAL; + } + } else if (fe->ops.info.type == FE_OFDM) { + dprintk(1, "%s() OFDM\n", __func__); + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + priv->freq_hz = params->frequency - 1750000; + break; + case BANDWIDTH_7_MHZ: + printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n"); + return -EINVAL; + case BANDWIDTH_8_MHZ: + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->video_standard = DTV8; + priv->freq_hz = params->frequency - 2750000; + break; + default: + printk(KERN_ERR "xc5000 bandwidth not set!\n"); + return -EINVAL; + } priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - default: + } else { + printk(KERN_ERR "xc5000 modulation type not supported!\n"); return -EINVAL; } @@ -717,7 +720,7 @@ static int xc5000_set_params(struct dvb_frontend *fe, return -EIO; } - xc_tune_channel(priv, priv->freq_hz); + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); if (debug) xc_debug_dump(priv); @@ -744,8 +747,6 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) return ret; } -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); - static int xc5000_set_analog_params(struct dvb_frontend *fe, struct analog_parameters *params) { @@ -826,7 +827,7 @@ tune_channel: return -EREMOTEIO; } - xc_tune_channel(priv, priv->freq_hz); + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); if (debug) xc_debug_dump(priv); @@ -894,18 +895,18 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) static int xc5000_sleep(struct dvb_frontend *fe) { - struct xc5000_priv *priv = fe->tuner_priv; int ret; dprintk(1, "%s()\n", __func__); - /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized - * once shutdown without reloading the driver. Maybe I am not - * doing something right. - * - */ + /* Avoid firmware reload on slow devices */ + if (no_poweroff) + return 0; - ret = xc_shutdown(priv); + /* According to Xceive technical support, the "powerdown" register + was removed in newer versions of the firmware. The "supported" + way to sleep the tuner is to pull the reset pin low for 10ms */ + ret = xc5000_TunerReset(fe); if (ret != XC_RESULT_SUCCESS) { printk(KERN_ERR "xc5000: %s() unable to shutdown tuner\n", @@ -1010,7 +1011,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, /* Check if firmware has been loaded. It is possible that another instance of the driver has loaded the firmware. */ - if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) + if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) goto fail; switch (id) { diff --git a/linux/drivers/media/dvb/b2c2/flexcop-common.h b/linux/drivers/media/dvb/b2c2/flexcop-common.h index cee2956cb..9d66105d3 100644 --- a/linux/drivers/media/dvb/b2c2/flexcop-common.h +++ b/linux/drivers/media/dvb/b2c2/flexcop-common.h @@ -1,9 +1,7 @@ /* - * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III - * - * flexcop-common.h - common header file for device-specific source files also. - * - * see flexcop.c for copyright information. + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-common.h - common header file for device-specific source files + * see flexcop.c for copyright information */ #ifndef __FLEXCOP_COMMON_H__ #define __FLEXCOP_COMMON_H__ diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index f7afab594..3f485bf13 100644 --- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -1,34 +1,27 @@ /* - * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III - * - * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC. - * - * see flexcop.c for copyright information. + * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling + * see flexcop.c for copyright information */ #include <media/tuner.h> - #include "flexcop.h" - -#include "stv0299.h" -#include "mt352.h" -#include "nxt200x.h" -#include "bcm3510.h" -#include "stv0297.h" #include "mt312.h" -#include "lgdt330x.h" -#include "dvb-pll.h" -#include "tuner-simple.h" - +#include "stv0299.h" #include "s5h1420.h" #include "itd1000.h" - -#include "cx24123.h" #include "cx24113.h" - +#include "cx24123.h" #include "isl6421.h" +#include "mt352.h" +#include "bcm3510.h" +#include "nxt200x.h" +#include "dvb-pll.h" +#include "lgdt330x.h" +#include "tuner-simple.h" +#include "stv0297.h" /* lnb control */ - +#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { struct flexcop_device *fc = fe->dvb->priv; @@ -37,65 +30,62 @@ static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage v = fc->read_ibi_reg(fc, misc_204); switch (voltage) { - case SEC_VOLTAGE_OFF: - v.misc_204.ACPI1_sig = 1; - break; - case SEC_VOLTAGE_13: - v.misc_204.ACPI1_sig = 0; - v.misc_204.LNB_L_H_sig = 0; - break; - case SEC_VOLTAGE_18: - v.misc_204.ACPI1_sig = 0; - v.misc_204.LNB_L_H_sig = 1; - break; - default: - err("unknown SEC_VOLTAGE value"); - return -EINVAL; + case SEC_VOLTAGE_OFF: + v.misc_204.ACPI1_sig = 1; + break; + case SEC_VOLTAGE_13: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 0; + break; + case SEC_VOLTAGE_18: + v.misc_204.ACPI1_sig = 0; + v.misc_204.LNB_L_H_sig = 1; + break; + default: + err("unknown SEC_VOLTAGE value"); + return -EINVAL; } return fc->write_ibi_reg(fc, misc_204, v); } +#endif +#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \ + || defined(CONFIG_DVB_MT312_MODULE) static int flexcop_sleep(struct dvb_frontend* fe) { struct flexcop_device *fc = fe->dvb->priv; -/* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */ - if (fc->fe_sleep) return fc->fe_sleep(fe); - -/* v.misc_204.ACPI3_sig = 1; - fc->write_ibi_reg(fc,misc_204,v);*/ - return 0; } +#endif +/* SkyStar2 DVB-S rev 2.3 */ +#if defined(CONFIG_DVB_MT312_MODULE) static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) { - /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ +/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ struct flexcop_device *fc = fe->dvb->priv; flexcop_ibi_value v; u16 ax; v.raw = 0; - deb_tuner("tone = %u\n",tone); switch (tone) { - case SEC_TONE_ON: - ax = 0x01ff; - break; - case SEC_TONE_OFF: - ax = 0; - break; - default: - err("unknown SEC_TONE value"); - return -EINVAL; + case SEC_TONE_ON: + ax = 0x01ff; + break; + case SEC_TONE_OFF: + ax = 0; + break; + default: + err("unknown SEC_TONE value"); + return -EINVAL; } v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ - v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; - return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); } @@ -110,17 +100,16 @@ static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) { int i, par = 1, d; - for (i = 7; i >= 0; i--) { d = (data >> i) & 1; par ^= d; flexcop_diseqc_send_bit(fe, d); } - flexcop_diseqc_send_bit(fe, par); } -static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst) +static int flexcop_send_diseqc_msg(struct dvb_frontend *fe, + int len, u8 *msg, unsigned long burst) { int i; @@ -129,7 +118,6 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un for (i = 0; i < len; i++) flexcop_diseqc_send_byte(fe,msg[i]); - mdelay(16); if (burst != -1) { @@ -146,50 +134,110 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un return 0; } -static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) { return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); } -static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int flexcop_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t minicmd) { return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); } -/* dvb-s stv0299 */ -static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +static struct mt312_config skystar23_samsung_tbdu18132_config = { + .demod_address = 0x0e, +}; + +static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, + .len = sizeof(buf) }; + struct flexcop_device *fc = fe->dvb->priv; + div = (params->frequency + (125/2)) / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + buf[2] = 0x84 | ((div >> 10) & 0x60); + buf[3] = 0x80; + + if (params->frequency < 1550000) + buf[3] |= 0x02; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static void skystar2_rev23_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(mt312_attach, + &skystar23_samsung_tbdu18132_config, i2c); + if (fc->fe != NULL) { + struct dvb_frontend_ops *ops = &fc->fe->ops; + ops->tuner_ops.set_params \ + = skystar23_samsung_tbdu18132_tuner_set_params; + ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; + ops->diseqc_send_burst = flexcop_diseqc_send_burst; + ops->set_tone = flexcop_set_tone; + ops->set_voltage = flexcop_set_voltage; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; + fc->dev_type = FC_SKY_REV23; + } +} +#endif + +/* SkyStar2 DVB-S rev 2.6 */ +#if defined(CONFIG_DVB_STV0299_MODULE) +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) { u8 aclk = 0; u8 bclk = 0; - if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } - else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } - else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } - else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } - else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } - else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } - - stv0299_writereg (fe, 0x13, aclk); - stv0299_writereg (fe, 0x14, bclk); - stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); + if (srate < 1500000) { + aclk = 0xb7; bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; bclk = 0x51; + } + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); return 0; } -static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { u8 buf[4]; u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct i2c_msg msg = { + .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; struct flexcop_device *fc = fe->dvb->priv; - div = params->frequency / 125; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; - buf[2] = 0x84; /* 0xC4 */ + buf[2] = 0x84; /* 0xC4 */ buf[3] = 0x08; if (params->frequency < 1500000) @@ -203,48 +251,48 @@ static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dv } static u8 samsung_tbmu24112_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x35, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0xC3, - 0x0C, 0x00, - 0x0D, 0x81, - 0x0E, 0x23, - 0x0F, 0x12, - 0x10, 0x7E, - 0x11, 0x84, - 0x12, 0xB9, - 0x13, 0x88, - 0x14, 0x89, - 0x15, 0xC9, - 0x16, 0x00, - 0x17, 0x5C, - 0x18, 0x00, - 0x19, 0x00, - 0x1A, 0x00, - 0x1C, 0x00, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x3A, - 0x20, 0x2E, - 0x21, 0x80, - 0x22, 0xFF, - 0x23, 0xC1, - 0x28, 0x00, - 0x29, 0x1E, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFE, - 0x34, 0x93, - 0xff, 0xff, + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, }; static struct stv0299_config samsung_tbmu24112_config = { @@ -259,27 +307,136 @@ static struct stv0299_config samsung_tbmu24112_config = { .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, }; -/* dvb-t mt352 */ -static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) +static void skystar2_rev26_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) { - static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; + fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); + if (fc->fe != NULL) { + struct dvb_frontend_ops *ops = &fc->fe->ops; + ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params; + ops->set_voltage = flexcop_set_voltage; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; + } +} +#endif + +/* SkyStar2 DVB-S rev 2.7 */ +#if defined(CONFIG_DVB_S5H1420_MODULE) +static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { + .demod_address = 0x53, + .invert = 1, + .repeated_start_workaround = 1, + .serial_mpeg = 1, +}; + +static struct itd1000_config skystar2_rev2_7_itd1000_config = { + .i2c_address = 0x61, +}; + +static void skystar2_rev27_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + /* enable no_base_addr - no repeated start when reading */ + fc->fc_i2c_adap[0].no_base_addr = 1; + fc->fe = dvb_attach(s5h1420_attach, + &skystar2_rev2_7_s5h1420_config, i2c); + if (fc->fe != NULL) { + flexcop_ibi_value r108; + struct i2c_adapter *i2c_tuner \ + = s5h1420_get_tuner_i2c_adapter(fc->fe); + struct dvb_frontend_ops *ops = &fc->fe->ops; + + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; + + /* enable no_base_addr - no repeated start when reading */ + fc->fc_i2c_adap[2].no_base_addr = 1; + if (dvb_attach(isl6421_attach, fc->fe, + &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL) + err("ISL6421 could NOT be attached"); + else + info("ISL6421 successfully attached"); + + /* the ITD1000 requires a lower i2c clock - is it a problem ? */ + r108.raw = 0x00000506; + fc->write_ibi_reg(fc, tw_sm_c_108, r108); + if (i2c_tuner) { + if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, + &skystar2_rev2_7_itd1000_config) == NULL) + err("ITD1000 could NOT be attached"); + else + info("ITD1000 successfully attached"); + } + } else + fc->fc_i2c_adap[0].no_base_addr = 0; + /* for the next devices we need it again */ +} +#endif + +/* SkyStar2 rev 2.8 */ +#if defined(CONFIG_DVB_CX24123_MODULE) +static struct cx24123_config skystar2_rev2_8_cx24123_config = { + .demod_address = 0x55, + .dont_use_pll = 1, + .agc_callback = cx24113_agc_callback, +}; + +static const struct cx24113_config skystar2_rev2_8_cx24113_config = { + .i2c_addr = 0x54, + .xtal_khz = 10111, +}; + +static void skystar2_rev28_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(cx24123_attach, + &skystar2_rev2_8_cx24123_config, i2c); + if (fc->fe != NULL) { + struct i2c_adapter *i2c_tuner \ + = cx24123_get_tuner_i2c_adapter(fc->fe); + if (i2c_tuner != NULL) { + if (dvb_attach(cx24113_attach, fc->fe, + &skystar2_rev2_8_cx24113_config, + i2c_tuner) == NULL) + err("CX24113 could NOT be attached"); + else + info("CX24113 successfully attached"); + } + + fc->fc_i2c_adap[2].no_base_addr = 1; + if (dvb_attach(isl6421_attach, fc->fe, + &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL) + err("ISL6421 could NOT be attached"); + else + info("ISL6421 successfully attached"); + /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an + * IR-receiver (PIC16F818) - but the card has no input for that ??? */ + } +} +#endif + +/* AirStar DVB-T */ +#if defined(CONFIG_DVB_MT352_MODULE) +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe) +{ + static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d }; + static u8 mt352_reset[] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 }; static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); udelay(2000); mt352_write(fe, mt352_reset, sizeof(mt352_reset)); mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - return 0; } -static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len) +static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len) { u32 div; unsigned char bs = 0; @@ -287,19 +444,20 @@ static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_fro if (buf_len < 5) return -EINVAL; - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ +#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; - if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; - if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; + if (params->frequency >= 48000000 && params->frequency <= 154000000) \ + bs = 0x09; + if (params->frequency >= 161000000 && params->frequency <= 439000000) \ + bs = 0x0a; + if (params->frequency >= 447000000 && params->frequency <= 863000000) \ + bs = 0x08; pllbuf[0] = 0x61; pllbuf[1] = div >> 8; pllbuf[2] = div & 0xff; pllbuf[3] = 0xcc; pllbuf[4] = bs; - return 5; } @@ -308,70 +466,88 @@ static struct mt352_config samsung_tdtc9251dh0_config = { .demod_init = samsung_tdtc9251dh0_demod_init, }; -static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +static void airstar_dvbt_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); + if (fc->fe != NULL) + fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; +} +#endif + +/* AirStar ATSC 1st generation */ +#if defined(CONFIG_DVB_BCM3510_MODULE) +static int flexcop_fe_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char* name) { struct flexcop_device *fc = fe->dvb->priv; return request_firmware(fw, name, fc->dev); } -static struct lgdt330x_config air2pc_atsc_hd5000_config = { - .demod_address = 0x59, - .demod_chip = LGDT3303, - .serial_mpeg = 0x04, - .clock_polarity_flip = 1, -}; - -static struct nxt200x_config samsung_tbmv_config = { - .demod_address = 0x0a, -}; - static struct bcm3510_config air2pc_atsc_first_gen_config = { .demod_address = 0x0f, .request_firmware = flexcop_fe_request_firmware, }; -static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static void airstar_atsc1_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) { - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct flexcop_device *fc = fe->dvb->priv; - - div = (params->frequency + (125/2)) / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - buf[2] = 0x84 | ((div >> 10) & 0x60); - buf[3] = 0x80; + fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); +} +#endif - if (params->frequency < 1550000) - buf[3] |= 0x02; +/* AirStar ATSC 2nd generation */ +#if defined(CONFIG_DVB_NXT200X_MODULE) +static struct nxt200x_config samsung_tbmv_config = { + .demod_address = 0x0a, +}; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; +static void airstar_atsc2_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); + if (fc->fe != NULL) + dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, + DVB_PLL_SAMSUNG_TBMV); } +#endif -static struct mt312_config skystar23_samsung_tbdu18132_config = { - - .demod_address = 0x0e, +/* AirStar ATSC 3rd generation */ +#if defined(CONFIG_DVB_LGDT330X_MODULE) +static struct lgdt330x_config air2pc_atsc_hd5000_config = { + .demod_address = 0x59, + .demod_chip = LGDT3303, + .serial_mpeg = 0x04, + .clock_polarity_flip = 1, }; +static void airstar_atsc3_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) +{ + fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); + if (fc->fe != NULL) { + dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, + TUNER_LG_TDVS_H06XF); + } +} +#endif + +/* CableStar2 DVB-C */ +#if defined(CONFIG_DVB_STV0297_MODULE) static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) + struct dvb_frontend_parameters *fep) { struct flexcop_device *fc = fe->dvb->priv; u8 buf[4]; u16 div; int ret; -/* 62.5 kHz * 10 */ +/* 62.5 kHz * 10 */ #define REF_FREQ 625 #define FREQ_OFFSET 36125 - div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz + div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ; +/* 4 MHz = 4000 KHz */ buf[0] = (u8)( div >> 8) & 0x7f; buf[1] = (u8) div & 0xff; @@ -384,11 +560,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */ buf[2] = 0x95; -// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5 -// 47 - 153 0 * 0 0 0 0 0 1 0x01 -// 153 - 430 0 * 0 0 0 0 1 0 0x02 -// 430 - 822 0 * 0 0 1 0 0 0 0x08 -// 822 - 862 1 * 0 0 1 0 0 0 0x88 +/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5 + * 47 - 153 0 * 0 0 0 0 0 1 0x01 + * 153 - 430 0 * 0 0 0 0 1 0 0x02 + * 430 - 822 0 * 0 0 1 0 0 0 0x08 + * 822 - 862 1 * 0 0 1 0 0 0 0x88 */ if (fep->frequency <= 153000000) buf[3] = 0x01; else if (fep->frequency <= 430000000) buf[3] = 0x02; @@ -397,11 +573,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]); + deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency, + buf[0], buf[1], buf[2], buf[3]); ret = fc->i2c_request(&fc->fc_i2c_adap[2], - FC_WRITE, 0x61, buf[0], &buf[1], 3); + FC_WRITE, 0x61, buf[0], &buf[1], 3); deb_tuner("tuner write returned: %d\n",ret); - return ret; } @@ -481,190 +657,75 @@ static u8 alps_tdee4_stv0297_inittab[] = { static struct stv0297_config alps_tdee4_stv0297_config = { .demod_address = 0x1c, .inittab = alps_tdee4_stv0297_inittab, -// .invert = 1, -// .pll_set = alps_tdee4_stv0297_pll_set, }; - -/* SkyStar2 rev2.7 (a/u) */ -static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { - .demod_address = 0x53, - .invert = 1, - .repeated_start_workaround = 1, - .serial_mpeg = 1, -}; - -static struct itd1000_config skystar2_rev2_7_itd1000_config = { - .i2c_address = 0x61, -}; - -/* SkyStar2 rev2.8 */ -static struct cx24123_config skystar2_rev2_8_cx24123_config = { - .demod_address = 0x55, - .dont_use_pll = 1, - .agc_callback = cx24113_agc_callback, -}; - -static const struct cx24113_config skystar2_rev2_8_cx24113_config = { - .i2c_addr = 0x54, - .xtal_khz = 10111, -}; - -/* try to figure out the frontend, each card/box can have on of the following list */ -int flexcop_frontend_init(struct flexcop_device *fc) +static void cablestar2_attach(struct flexcop_device *fc, + struct i2c_adapter *i2c) { - struct dvb_frontend_ops *ops; - struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap; - struct i2c_adapter *i2c_tuner; - - /* enable no_base_addr - no repeated start when reading */ - fc->fc_i2c_adap[0].no_base_addr = 1; - fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c); - if (fc->fe != NULL) { - flexcop_ibi_value r108; - i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe); - ops = &fc->fe->ops; - - fc->fe_sleep = ops->sleep; - ops->sleep = flexcop_sleep; - - fc->dev_type = FC_SKY_REV27; - - /* enable no_base_addr - no repeated start when reading */ - fc->fc_i2c_adap[2].no_base_addr = 1; - if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL) - err("ISL6421 could NOT be attached"); - else - info("ISL6421 successfully attached"); - - /* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */ - r108.raw = 0x00000506; - fc->write_ibi_reg(fc, tw_sm_c_108, r108); - if (i2c_tuner) { - if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL) - err("ITD1000 could NOT be attached"); - else - info("ITD1000 successfully attached"); - } - goto fe_found; - } - fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */ - - /* try the sky v2.8 (cx24123, isl6421) */ - fc->fe = dvb_attach(cx24123_attach, - &skystar2_rev2_8_cx24123_config, i2c); - if (fc->fe != NULL) { - i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe); - if (i2c_tuner != NULL) { - if (dvb_attach(cx24113_attach, fc->fe, - &skystar2_rev2_8_cx24113_config, - i2c_tuner) == NULL) - err("CX24113 could NOT be attached"); - else - info("CX24113 successfully attached"); - } - - fc->dev_type = FC_SKY_REV28; - - fc->fc_i2c_adap[2].no_base_addr = 1; - if (dvb_attach(isl6421_attach, fc->fe, - &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL) - err("ISL6421 could NOT be attached"); - else - info("ISL6421 successfully attached"); - - /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an - * IR-receiver (PIC16F818) - but the card has no input for - * that ??? */ - - goto fe_found; - } - - /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ - fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); - if (fc->fe != NULL) { - ops = &fc->fe->ops; - - ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params; - - ops->set_voltage = flexcop_set_voltage; - - fc->fe_sleep = ops->sleep; - ops->sleep = flexcop_sleep; - - fc->dev_type = FC_SKY_REV26; - goto fe_found; - } - - /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */ - fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_AIR_DVBT; - fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; - goto fe_found; - } - - /* try the air atsc 2nd generation (nxt2002) */ - fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_AIR_ATSC2; - dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV); - goto fe_found; - } - - fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_AIR_ATSC3; - dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, - TUNER_LG_TDVS_H06XF); - goto fe_found; - } - - /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ - fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_AIR_ATSC1; - goto fe_found; - } - - /* try the cable dvb (stv0297) */ fc->fc_i2c_adap[0].no_base_addr = 1; fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); - if (fc->fe != NULL) { - fc->dev_type = FC_CABLE; - fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; - goto fe_found; - } - fc->fc_i2c_adap[0].no_base_addr = 0; - - /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ - fc->fe = dvb_attach(mt312_attach, - &skystar23_samsung_tbdu18132_config, i2c); - if (fc->fe != NULL) { - ops = &fc->fe->ops; - - ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params; - - ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; - ops->diseqc_send_burst = flexcop_diseqc_send_burst; - ops->set_tone = flexcop_set_tone; - ops->set_voltage = flexcop_set_voltage; - - fc->fe_sleep = ops->sleep; - ops->sleep = flexcop_sleep; + if (fc->fe != NULL) + fc->fe->ops.tuner_ops.set_params \ + = alps_tdee4_stv0297_tuner_set_params; + else + fc->fc_i2c_adap[0].no_base_addr = 0; +} +#endif + +static struct { + flexcop_device_type_t type; + void (*attach)(struct flexcop_device *, struct i2c_adapter *); +} flexcop_frontends[] = { +#if defined(CONFIG_DVB_S5H1420_MODULE) + { FC_SKY_REV27, skystar2_rev27_attach }, +#endif +#if defined(CONFIG_DVB_CX24123_MODULE) + { FC_SKY_REV28, skystar2_rev28_attach }, +#endif +#if defined(CONFIG_DVB_STV0299_MODULE) + { FC_SKY_REV26, skystar2_rev26_attach }, +#endif +#if defined(CONFIG_DVB_MT352_MODULE) + { FC_AIR_DVBT, airstar_dvbt_attach }, +#endif +#if defined(CONFIG_DVB_NXT200X_MODULE) + { FC_AIR_ATSC2, airstar_atsc2_attach }, +#endif +#if defined(CONFIG_DVB_LGDT330X_MODULE) + { FC_AIR_ATSC3, airstar_atsc3_attach }, +#endif +#if defined(CONFIG_DVB_BCM3510_MODULE) + { FC_AIR_ATSC1, airstar_atsc1_attach }, +#endif +#if defined(CONFIG_DVB_STV0297_MODULE) + { FC_CABLE, cablestar2_attach }, +#endif +#if defined(CONFIG_DVB_MT312_MODULE) + { FC_SKY_REV23, skystar2_rev23_attach }, +#endif +}; - fc->dev_type = FC_SKY_REV23; - goto fe_found; +/* try to figure out the frontend */ +int flexcop_frontend_init(struct flexcop_device *fc) +{ + int i; + for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) { + /* type needs to be set before, because of some workarounds + * done based on the probed card type */ + fc->dev_type = flexcop_frontends[i].type; + flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap); + if (fc->fe != NULL) + goto fe_found; } - + fc->dev_type = FC_UNK; err("no frontend driver found for this B2C2/FlexCop adapter"); return -ENODEV; fe_found: info("found '%s' .", fc->fe->ops.info.name); if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { + struct dvb_frontend_ops *ops = &fc->fe->ops; err("frontend registration failed!"); - ops = &fc->fe->ops; if (ops->release != NULL) ops->release(fc->fe); fc->fe = NULL; @@ -680,6 +741,5 @@ void flexcop_frontend_exit(struct flexcop_device *fc) dvb_unregister_frontend(fc->fe); dvb_frontend_detach(fc->fe); } - fc->init_state &= ~FC_STATE_FE_INIT; } diff --git a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c index 06a90f67e..df4d6e8d9 100644 --- a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -200,7 +200,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); if (ret < 0) { - err("i2c master_xfer failed"); + deb_i2c("i2c master_xfer failed"); break; } } diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c index c35fbb8d8..6d6121eb5 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.c +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c @@ -244,19 +244,13 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; - int ret; - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); + if (dmxdev->exit) return -ENODEV; - } - //mutex_lock(&dmxdev->mutex); - ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); - //mutex_unlock(&dmxdev->mutex); - return ret; + return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); } static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index da2890b22..d359f6841 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -554,6 +554,7 @@ restart: if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { /* got signal or quitting */ + fepriv->exit = 1; break; } diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c index 57c678892..5d9aacd0a 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9015.c +++ b/linux/drivers/media/dvb/dvb-usb/af9015.c @@ -1267,6 +1267,7 @@ static struct usb_device_id af9015_usb_table[] = { /* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1537,7 +1538,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 2, /* max 9 */ + .num_device_descs = 3, /* max 9 */ .devices = { { .name = "AverMedia AVerTV Volar GPS 805 (A805)", @@ -1550,6 +1551,11 @@ static struct dvb_usb_device_properties af9015_properties[] = { .cold_ids = {&af9015_usb_table[22], NULL}, .warm_ids = {NULL}, }, + { + .name = "KWorld Digial MC-810", + .cold_ids = {&af9015_usb_table[23], NULL}, + .warm_ids = {NULL}, + }, } }, }; diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index e39993df0..eda025714 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1346,9 +1346,9 @@ static int dib0700_xc5000_tuner_callback(void *priv, int component, if (command == XC5000_TUNER_RESET) { /* Reset the tuner */ dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); - msleep(330); /* from Windows USB trace */ + msleep(10); dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); - msleep(330); /* from Windows USB trace */ + msleep(10); } else { err("xc5000: unknown tuner callback command: %d\n", command); return -EINVAL; @@ -1498,6 +1498,9 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) }, { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) }, /* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) }, + { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1731,8 +1734,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[30], NULL }, { NULL }, }, - { "Terratec Cinergy T USB XXS", - { &dib0700_usb_id_table[33], NULL }, + { "Terratec Cinergy T USB XXS/ T3", + { &dib0700_usb_id_table[33], + &dib0700_usb_id_table[52], NULL }, { NULL }, }, { "Elgato EyeTV DTT", @@ -1793,8 +1797,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[36], NULL }, { NULL }, }, - { "Terratec Cinergy DT USB XS Diversity", - { &dib0700_usb_id_table[43], NULL }, + { "Terratec Cinergy DT USB XS Diversity/ T5", + { &dib0700_usb_id_table[43], + &dib0700_usb_id_table[53], NULL}, { NULL }, }, { "Sony PlayTV", @@ -1821,7 +1826,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 7, + .num_device_descs = 8, .devices = { { "Terratec Cinergy HT USB XE", { &dib0700_usb_id_table[27], NULL }, @@ -1851,6 +1856,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[48], NULL }, { NULL }, }, + { "Leadtek WinFast DTV Dongle H", + { &dib0700_usb_id_table[51], NULL }, + { NULL }, + }, + }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/linux/drivers/media/dvb/dvb-usb/dibusb-common.c b/linux/drivers/media/dvb/dvb-usb/dibusb-common.c index d774879df..99b3b9a43 100644 --- a/linux/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/linux/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -133,14 +133,17 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num for (i = 0; i < num; i++) { /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0 + && (msg[i+1].flags & I2C_M_RD)) { if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len, msg[i+1].buf,msg[i+1].len) < 0) break; i++; - } else + } else if ((msg[i].flags & I2C_M_RD) == 0) { if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) break; + } else + break; } mutex_unlock(&d->i2c_mutex); diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 6a4062d5d..7340ef4cd 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -105,6 +105,7 @@ #define USB_PID_KWORLD_395U 0xe396 #define USB_PID_KWORLD_395U_2 0xe39b #define USB_PID_KWORLD_395U_3 0xe395 +#define USB_PID_KWORLD_MC810 0xc810 #define USB_PID_KWORLD_PC160_2T 0xc160 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df @@ -180,6 +181,8 @@ #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 +#define USB_PID_TERRATEC_T3 0x10a0 +#define USB_PID_TERRATEC_T5 0x10a1 #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e #define USB_PID_PINNACLE_PCTV2000E 0x022c #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 @@ -224,6 +227,7 @@ #define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 +#define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 #define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029 #define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 diff --git a/linux/drivers/media/dvb/dvb-usb/gp8psk.c b/linux/drivers/media/dvb/dvb-usb/gp8psk.c index 3dd684386..003d97f8c 100644 --- a/linux/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/linux/drivers/media/dvb/dvb-usb/gp8psk.c @@ -223,7 +223,7 @@ static struct usb_device_id gp8psk_usb_table [] = { { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, +/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ { 0 }, }; MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); @@ -254,7 +254,7 @@ static struct dvb_usb_device_properties gp8psk_properties = { .generic_bulk_ctrl_endpoint = 0x01, - .num_device_descs = 4, + .num_device_descs = 3, .devices = { { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", .cold_ids = { &gp8psk_usb_table[0], NULL }, @@ -268,10 +268,12 @@ static struct dvb_usb_device_properties gp8psk_properties = { .cold_ids = { NULL }, .warm_ids = { &gp8psk_usb_table[3], NULL }, }, +#if 0 { .name = "Genpix SkyWalker-CW3K DVB-S receiver", .cold_ids = { NULL }, .warm_ids = { &gp8psk_usb_table[4], NULL }, }, +#endif { NULL }, } }; diff --git a/linux/drivers/media/dvb/firewire/firedtv-1394.c b/linux/drivers/media/dvb/firewire/firedtv-1394.c index 4e207658c..2b6eeeab5 100644 --- a/linux/drivers/media/dvb/firewire/firedtv-1394.c +++ b/linux/drivers/media/dvb/firewire/firedtv-1394.c @@ -225,7 +225,7 @@ fail_free: static int node_remove(struct device *dev) { - struct firedtv *fdtv = dev->driver_data; + struct firedtv *fdtv = dev_get_drvdata(dev); fdtv_dvb_unregister(fdtv); @@ -242,7 +242,7 @@ static int node_remove(struct device *dev) static int node_update(struct unit_directory *ud) { - struct firedtv *fdtv = ud->device.driver_data; + struct firedtv *fdtv = dev_get_drvdata(&ud->device); if (fdtv->isochannel >= 0) cmp_establish_pp_connection(fdtv, fdtv->subunit, diff --git a/linux/drivers/media/dvb/firewire/firedtv-dvb.c b/linux/drivers/media/dvb/firewire/firedtv-dvb.c index 9d308dd32..5742fde79 100644 --- a/linux/drivers/media/dvb/firewire/firedtv-dvb.c +++ b/linux/drivers/media/dvb/firewire/firedtv-dvb.c @@ -268,7 +268,7 @@ struct firedtv *fdtv_alloc(struct device *dev, if (!fdtv) return NULL; - dev->driver_data = fdtv; + dev_set_drvdata(dev, fdtv); fdtv->device = dev; fdtv->isochannel = -1; fdtv->voltage = 0xff; diff --git a/linux/drivers/media/dvb/firewire/firedtv-rc.c b/linux/drivers/media/dvb/firewire/firedtv-rc.c index 46a6324d7..27bca2e28 100644 --- a/linux/drivers/media/dvb/firewire/firedtv-rc.c +++ b/linux/drivers/media/dvb/firewire/firedtv-rc.c @@ -18,7 +18,7 @@ #include "firedtv.h" /* fixed table with older keycodes, geared towards MythTV */ -const static u16 oldtable[] = { +static const u16 oldtable[] = { /* code from device: 0x4501...0x451f */ @@ -62,7 +62,7 @@ const static u16 oldtable[] = { }; /* user-modifiable table for a remote as sold in 2008 */ -const static u16 keytable[] = { +static const u16 keytable[] = { /* code from device: 0x0300...0x031f */ diff --git a/linux/drivers/media/dvb/frontends/af9013.c b/linux/drivers/media/dvb/frontends/af9013.c index 937715a96..d12d99802 100644 --- a/linux/drivers/media/dvb/frontends/af9013.c +++ b/linux/drivers/media/dvb/frontends/af9013.c @@ -1456,7 +1456,7 @@ static int af9013_download_firmware(struct af9013_state *state) af9013_ops.info.name); /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, &state->i2c->dev); + ret = request_firmware(&fw, fw_file, state->i2c->dev.parent); if (ret) { err("did not find the firmware file. (%s) " "Please see linux/Documentation/dvb/ for more details" \ diff --git a/linux/drivers/media/dvb/frontends/cx24116.c b/linux/drivers/media/dvb/frontends/cx24116.c index b5ff0b6a8..fddd27bd1 100644 --- a/linux/drivers/media/dvb/frontends/cx24116.c +++ b/linux/drivers/media/dvb/frontends/cx24116.c @@ -492,7 +492,7 @@ static int cx24116_firmware_ondemand(struct dvb_frontend *fe) printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE); ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, - &state->i2c->dev); + state->i2c->dev.parent); printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); if (ret) { diff --git a/linux/drivers/media/dvb/frontends/drx397xD.c b/linux/drivers/media/dvb/frontends/drx397xD.c index 0bdb933d0..95eff4a81 100644 --- a/linux/drivers/media/dvb/frontends/drx397xD.c +++ b/linux/drivers/media/dvb/frontends/drx397xD.c @@ -124,10 +124,10 @@ static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix) } memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); - if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) { + rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent); + if (rc != 0) { printk(KERN_ERR "%s: Firmware \"%s\" not available\n", mod_name, fw[ix].name); - rc = -ENOENT; goto exit_err; } diff --git a/linux/drivers/media/dvb/frontends/mt312.c b/linux/drivers/media/dvb/frontends/mt312.c index 5ac9b1592..a621f7279 100644 --- a/linux/drivers/media/dvb/frontends/mt312.c +++ b/linux/drivers/media/dvb/frontends/mt312.c @@ -77,7 +77,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) { - printk(KERN_ERR "%s: ret == %d\n", __func__, ret); + printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret); return -EREMOTEIO; } diff --git a/linux/drivers/media/dvb/frontends/nxt200x.c b/linux/drivers/media/dvb/frontends/nxt200x.c index 846350bc4..748f95b22 100644 --- a/linux/drivers/media/dvb/frontends/nxt200x.c +++ b/linux/drivers/media/dvb/frontends/nxt200x.c @@ -880,7 +880,8 @@ static int nxt2002_init(struct dvb_frontend* fe) /* request the firmware, this will block until someone uploads it */ printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev); + ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, + state->i2c->dev.parent); printk("nxt2002: Waiting for firmware upload(2)...\n"); if (ret) { printk("nxt2002: No firmware uploaded (timeout or file not found?)\n"); @@ -944,7 +945,8 @@ static int nxt2004_init(struct dvb_frontend* fe) /* request the firmware, this will block until someone uploads it */ printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE); - ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev); + ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, + state->i2c->dev.parent); printk("nxt2004: Waiting for firmware upload(2)...\n"); if (ret) { printk("nxt2004: No firmware uploaded (timeout or file not found?)\n"); diff --git a/linux/drivers/media/dvb/frontends/or51132.c b/linux/drivers/media/dvb/frontends/or51132.c index 5ed32544d..8133ea3cd 100644 --- a/linux/drivers/media/dvb/frontends/or51132.c +++ b/linux/drivers/media/dvb/frontends/or51132.c @@ -340,7 +340,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe, } printk("or51132: Waiting for firmware upload(%s)...\n", fwname); - ret = request_firmware(&fw, fwname, &state->i2c->dev); + ret = request_firmware(&fw, fwname, state->i2c->dev.parent); if (ret) { printk(KERN_WARNING "or51132: No firmware up" "loaded(timeout or file not found?)\n"); diff --git a/linux/drivers/media/dvb/frontends/tda10048.c b/linux/drivers/media/dvb/frontends/tda10048.c index 3163aad5b..04596baa9 100644 --- a/linux/drivers/media/dvb/frontends/tda10048.c +++ b/linux/drivers/media/dvb/frontends/tda10048.c @@ -1,7 +1,7 @@ /* NXP TDA10048HN DVB OFDM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> + Copyright (C) 2009 Steven Toth <stoth@kernellabs.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 @@ -139,8 +139,8 @@ struct tda10048_state { struct i2c_adapter *i2c; - /* configuration settings */ - const struct tda10048_config *config; + /* We'll cache and update the attach config settings */ + struct tda10048_config config; struct dvb_frontend frontend; int fwloaded; @@ -202,12 +202,26 @@ static struct init_tab { { TDA10048_CONF_C4_2, 0x04 }, }; +static struct pll_tab { + u32 clk_freq_khz; + u32 if_freq_khz; + u8 m, n, p; +} pll_tab[] = { + { TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 }, +}; + static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) { + struct tda10048_config *config = &state->config; int ret; u8 buf[] = { reg, data }; struct i2c_msg msg = { - .addr = state->config->demod_address, + .addr = config->demod_address, .flags = 0, .buf = buf, .len = 2 }; dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data); @@ -222,13 +236,14 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data) static u8 tda10048_readreg(struct tda10048_state *state, u8 reg) { + struct tda10048_config *config = &state->config; int ret; u8 b0[] = { reg }; u8 b1[] = { 0 }; struct i2c_msg msg[] = { - { .addr = state->config->demod_address, + { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, + { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg); @@ -245,6 +260,7 @@ static u8 tda10048_readreg(struct tda10048_state *state, u8 reg) static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg, const u8 *data, u16 len) { + struct tda10048_config *config = &state->config; int ret = -EREMOTEIO; struct i2c_msg msg; u8 *buf; @@ -260,7 +276,7 @@ static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg, *buf = reg; memcpy(buf + 1, data, len); - msg.addr = state->config->demod_address; + msg.addr = config->demod_address; msg.flags = 0; msg.buf = buf; msg.len = len + 1; @@ -411,47 +427,47 @@ static int tda10048_set_bandwidth(struct dvb_frontend *fe, return 0; } -static int tda10048_set_pll(struct dvb_frontend *fe) +static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) { struct tda10048_state *state = fe->demodulator_priv; - int ret = 0; + struct tda10048_config *config = &state->config; + int i; + u32 if_freq_khz; - dprintk(1, "%s()\n", __func__); + dprintk(1, "%s(bw = %d)\n", __func__, bw); - if ((state->config->clk_freq_khz == TDA10048_CLK_4000) && - (state->config->if_freq_khz == TDA10048_IF_36130)) { - state->freq_if_hz = TDA10048_IF_36130 * 1000; - state->xtal_hz = TDA10048_CLK_4000 * 1000; - state->pll_mfactor = 10; - state->pll_nfactor = 0; - state->pll_pfactor = 0; - } else - if ((state->config->clk_freq_khz == TDA10048_CLK_16000) && - (state->config->if_freq_khz == TDA10048_IF_4300)) { - state->freq_if_hz = TDA10048_IF_4300 * 1000; - state->xtal_hz = TDA10048_CLK_16000 * 1000; - state->pll_mfactor = 10; - state->pll_nfactor = 3; - state->pll_pfactor = 0; - } else - if ((state->config->clk_freq_khz == TDA10048_CLK_16000) && - (state->config->if_freq_khz == TDA10048_IF_4000)) { - state->freq_if_hz = TDA10048_IF_4000 * 1000; - state->xtal_hz = TDA10048_CLK_16000 * 1000; - state->pll_mfactor = 10; - state->pll_nfactor = 3; - state->pll_pfactor = 0; - } else - if ((state->config->clk_freq_khz == TDA10048_CLK_16000) && - (state->config->if_freq_khz == TDA10048_IF_36130)) { - state->freq_if_hz = TDA10048_IF_36130 * 1000; - state->xtal_hz = TDA10048_CLK_16000 * 1000; - state->pll_mfactor = 10; - state->pll_nfactor = 3; - state->pll_pfactor = 0; - } else { - printk(KERN_ERR "%s() Incorrect attach settings\n", __func__); - ret = -EINVAL; + /* based on target bandwidth and clk we calculate pll factors */ + switch (bw) { + case BANDWIDTH_6_MHZ: + if_freq_khz = config->dtv6_if_freq_khz; + break; + case BANDWIDTH_7_MHZ: + if_freq_khz = config->dtv7_if_freq_khz; + break; + case BANDWIDTH_8_MHZ: + if_freq_khz = config->dtv8_if_freq_khz; + break; + default: + printk(KERN_ERR "%s() no default\n", __func__); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(pll_tab); i++) { + if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) && + (pll_tab[i].if_freq_khz == if_freq_khz)) { + + state->freq_if_hz = pll_tab[i].if_freq_khz * 1000; + state->xtal_hz = pll_tab[i].clk_freq_khz * 1000; + state->pll_mfactor = pll_tab[i].m; + state->pll_nfactor = pll_tab[i].n; + state->pll_pfactor = pll_tab[i].p; + break; + } + } + if (i == ARRAY_SIZE(pll_tab)) { + printk(KERN_ERR "%s() Incorrect attach settings\n", + __func__); + return -EINVAL; } dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz); @@ -466,22 +482,21 @@ static int tda10048_set_pll(struct dvb_frontend *fe) state->sample_freq /= (state->pll_pfactor + 4); dprintk(1, "- sample_freq = %d\n", state->sample_freq); - tda10048_set_phy2(fe, state->sample_freq, - state->config->if_freq_khz * 1000); - tda10048_set_wref(fe, state->sample_freq, state->bandwidth); - tda10048_set_invwref(fe, state->sample_freq, state->bandwidth); + /* Update the I/F */ + tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz); - return ret; + return 0; } static int tda10048_firmware_upload(struct dvb_frontend *fe) { struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; const struct firmware *fw; int ret; int pos = 0; int cnt; - u8 wlen = state->config->fwbulkwritelen; + u8 wlen = config->fwbulkwritelen; if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50)) wlen = TDA10048_BULKWRITE_200; @@ -492,7 +507,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe) TDA10048_DEFAULT_FIRMWARE); ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE, - &state->i2c->dev); + state->i2c->dev.parent); if (ret) { printk(KERN_ERR "%s: Upload failed. (file not found?)\n", __func__); @@ -687,9 +702,10 @@ static int tda10048_get_tps(struct tda10048_state *state, static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; dprintk(1, "%s(%d)\n", __func__, enable); - if (state->config->disable_gate_access) + if (config->disable_gate_access) return 0; if (enable) @@ -729,8 +745,11 @@ static int tda10048_set_frontend(struct dvb_frontend *fe, dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); - if (p->u.ofdm.bandwidth != state->bandwidth) + /* Update the I/F pll's if the bandwidth changes */ + if (p->u.ofdm.bandwidth != state->bandwidth) { + tda10048_set_if(fe, p->u.ofdm.bandwidth); tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth); + } if (fe->ops.tuner_ops.set_params) { @@ -753,6 +772,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe, static int tda10048_init(struct dvb_frontend *fe) { struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; int ret = 0, i; dprintk(1, "%s()\n", __func__); @@ -765,15 +785,13 @@ static int tda10048_init(struct dvb_frontend *fe) ret = tda10048_firmware_upload(fe); /* Set either serial or parallel */ - tda10048_output_mode(fe, state->config->output_mode); + tda10048_output_mode(fe, config->output_mode); /* Set inversion */ - tda10048_set_inversion(fe, state->config->inversion); + tda10048_set_inversion(fe, config->inversion); - /* Establish default PLL values */ - tda10048_set_pll(fe); - - /* Establish default bandwidth */ + /* Establish default RF values */ + tda10048_set_if(fe, BANDWIDTH_8_MHZ); tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ); /* Ensure we leave the gate closed */ @@ -1032,6 +1050,45 @@ static void tda10048_release(struct dvb_frontend *fe) kfree(state); } +static void tda10048_establish_defaults(struct dvb_frontend *fe) +{ + struct tda10048_state *state = fe->demodulator_priv; + struct tda10048_config *config = &state->config; + + /* Validate/default the config */ + if (config->dtv6_if_freq_khz == 0) { + config->dtv6_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv6_if_freq_khz); + } + + if (config->dtv7_if_freq_khz == 0) { + config->dtv7_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv7_if_freq_khz); + } + + if (config->dtv8_if_freq_khz == 0) { + config->dtv8_if_freq_khz = TDA10048_IF_4300; + printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->dtv8_if_freq_khz); + } + + if (config->clk_freq_khz == 0) { + config->clk_freq_khz = TDA10048_CLK_16000; + printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz " + "is not set (defaulting to %d)\n", + __func__, + config->clk_freq_khz); + } +} + static struct dvb_frontend_ops tda10048_ops; struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, @@ -1046,8 +1103,8 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, if (state == NULL) goto error; - /* setup the state */ - state->config = config; + /* setup the state and clone the config */ + memcpy(&state->config, config, sizeof(*config)); state->i2c = i2c; state->fwloaded = 0; state->bandwidth = BANDWIDTH_8_MHZ; @@ -1061,8 +1118,15 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; + /* Establish any defaults the the user didn't pass */ + tda10048_establish_defaults(&state->frontend); + /* Set the xtal and freq defaults */ - if (tda10048_set_pll(&state->frontend) != 0) + if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0) + goto error; + + /* Default bandwidth */ + if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0) goto error; /* Leave the gate closed */ diff --git a/linux/drivers/media/dvb/frontends/tda10048.h b/linux/drivers/media/dvb/frontends/tda10048.h index ee07b50e9..8828ceaf7 100644 --- a/linux/drivers/media/dvb/frontends/tda10048.h +++ b/linux/drivers/media/dvb/frontends/tda10048.h @@ -1,7 +1,7 @@ /* NXP TDA10048HN DVB OFDM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> + Copyright (C) 2009 Steven Toth <stoth@kernellabs.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 @@ -52,7 +52,9 @@ struct tda10048_config { #define TDA10048_IF_4500 4500 #define TDA10048_IF_4750 4750 #define TDA10048_IF_36130 36130 - u16 if_freq_khz; + u16 dtv6_if_freq_khz; + u16 dtv7_if_freq_khz; + u16 dtv8_if_freq_khz; #define TDA10048_CLK_4000 4000 #define TDA10048_CLK_16000 16000 diff --git a/linux/drivers/media/dvb/siano/Makefile b/linux/drivers/media/dvb/siano/Makefile index bcf93f482..c6644d909 100644 --- a/linux/drivers/media/dvb/siano/Makefile +++ b/linux/drivers/media/dvb/siano/Makefile @@ -1,4 +1,4 @@ -sms1xxx-objs := smscoreapi.o sms-cards.o +sms1xxx-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o diff --git a/linux/drivers/media/dvb/siano/sms-cards.c b/linux/drivers/media/dvb/siano/sms-cards.c index 63e4d0ec6..fda483f07 100644 --- a/linux/drivers/media/dvb/siano/sms-cards.c +++ b/linux/drivers/media/dvb/siano/sms-cards.c @@ -18,6 +18,7 @@ */ #include "sms-cards.h" +#include "smsir.h" static int sms_dbg; module_param_named(cards_dbg, sms_dbg, int, 0644); @@ -30,17 +31,14 @@ static struct sms_board sms_boards[] = { [SMS1XXX_BOARD_SIANO_STELLAR] = { .name = "Siano Stellar Digital Receiver", .type = SMS_STELLAR, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", }, [SMS1XXX_BOARD_SIANO_NOVA_A] = { .name = "Siano Nova A Digital Receiver", .type = SMS_NOVA_A0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", }, [SMS1XXX_BOARD_SIANO_NOVA_B] = { .name = "Siano Nova B Digital Receiver", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", }, [SMS1XXX_BOARD_SIANO_VEGA] = { .name = "Siano Vega Digital Receiver", @@ -65,6 +63,9 @@ static struct sms_board sms_boards[] = { .name = "Hauppauge WinTV MiniStick", .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .board_cfg.leds_power = 26, + .board_cfg.led0 = 27, + .board_cfg.led1 = 28, .led_power = 26, .led_lo = 27, .led_hi = 28, @@ -74,7 +75,9 @@ static struct sms_board sms_boards[] = { .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", .lna_ctrl = 29, + .board_cfg.foreign_lna0_ctrl = 29, .rf_switch = 17, + .board_cfg.rf_switch_uhf = 17, }, [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { .name = "Hauppauge WinTV MiniCard", diff --git a/linux/drivers/media/dvb/siano/sms-cards.h b/linux/drivers/media/dvb/siano/sms-cards.h index 64d74c59c..447481ab5 100644 --- a/linux/drivers/media/dvb/siano/sms-cards.h +++ b/linux/drivers/media/dvb/siano/sms-cards.h @@ -22,6 +22,7 @@ #include <linux/usb.h> #include "smscoreapi.h" +#include "smsir.h" #define SMS_BOARD_UNKNOWN 0 #define SMS1XXX_BOARD_SIANO_STELLAR 1 @@ -35,9 +36,44 @@ #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 +struct sms_board_gpio_cfg { + int lna_vhf_exist; + int lna_vhf_ctrl; + int lna_uhf_exist; + int lna_uhf_ctrl; + int lna_uhf_d_ctrl; + int lna_sband_exist; + int lna_sband_ctrl; + int lna_sband_d_ctrl; + int foreign_lna0_ctrl; + int foreign_lna1_ctrl; + int foreign_lna2_ctrl; + int rf_switch_vhf; + int rf_switch_uhf; + int rf_switch_sband; + int leds_power; + int led0; + int led1; + int led2; + int led3; + int led4; + int ir; + int eeprom_wp; + int mrc_sense; + int mrc_pdn_resetn; + int mrc_gp0; /* mrcs spi int */ + int mrc_gp1; + int mrc_gp2; + int mrc_gp3; + int mrc_gp4; + int host_spi_gsp_ts_int; +}; + struct sms_board { enum sms_device_type_st type; char *name, *fw[DEVICE_MODE_MAX]; + struct sms_board_gpio_cfg board_cfg; + enum ir_kb_type ir_kb_type; /* gpios */ int led_power, led_hi, led_lo, lna_ctrl, rf_switch; @@ -45,6 +81,8 @@ struct sms_board { struct sms_board *sms_get_board(int id); +extern struct smscore_device_t *coredev; + int sms_board_setup(struct smscore_device_t *coredev); #define SMS_LED_OFF 0 diff --git a/linux/drivers/media/dvb/siano/smscoreapi.c b/linux/drivers/media/dvb/siano/smscoreapi.c index 9a9db2588..16917016c 100644 --- a/linux/drivers/media/dvb/siano/smscoreapi.c +++ b/linux/drivers/media/dvb/siano/smscoreapi.c @@ -30,9 +30,13 @@ #include <linux/io.h> #include <linux/firmware.h> +#include <linux/wait.h> +#include <asm/byteorder.h> #include "smscoreapi.h" #include "sms-cards.h" +#include "smsir.h" +#include "smsendian.h" static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); @@ -348,6 +352,10 @@ int smscore_register_device(struct smsdevice_params_t *params, init_completion(&dev->init_device_done); init_completion(&dev->reload_start_done); init_completion(&dev->resume_done); + init_completion(&dev->ir_init_done); + + /* Buffer management */ + init_waitqueue_head(&dev->buffer_mng_waitq); /* alloc common buffer */ dev->common_buffer_size = params->buffer_size * params->num_buffers; @@ -403,6 +411,71 @@ int smscore_register_device(struct smsdevice_params_t *params, } EXPORT_SYMBOL_GPL(smscore_register_device); + +static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, + void *buffer, size_t size, struct completion *completion) { + int rc = coredev->sendrequest_handler(coredev->context, buffer, size); + if (rc < 0) { + sms_info("sendrequest returned error %d", rc); + return rc; + } + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ? + 0 : -ETIME; +} + +/** + * Starts & enables IR operations + * + * @return 0 on success, < 0 on error. + */ +static int smscore_init_ir(struct smscore_device_t *coredev) +{ + int ir_io; + int rc; + void *buffer; + + coredev->ir.input_dev = NULL; + ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; + if (ir_io) {/* only if IR port exist we use IR sub-module */ + sms_info("IR loading"); + rc = sms_ir_init(coredev); + + if (rc != 0) + sms_err("Error initialization DTV IR sub-module"); + else { + buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + + SMS_DMA_ALIGNMENT, + GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST2 *msg = + (struct SmsMsgData_ST2 *) + SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, + MSG_SMS_START_IR_REQ, + sizeof(struct SmsMsgData_ST2)); + msg->msgData[0] = coredev->ir.controller; + msg->msgData[1] = coredev->ir.timeout; + + smsendian_handle_tx_message( + (struct SmsMsgHdr_ST2 *)msg); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->xMsgHeader. msgLength, + &coredev->ir_init_done); + + kfree(buffer); + } else + sms_err + ("Sending IR initialization message failed"); + } + } else + sms_info("IR port has not been detected"); + + return 0; +} + /** * sets initial device mode and notifies client hotplugs that device is ready * @@ -423,6 +496,7 @@ int smscore_start_device(struct smscore_device_t *coredev) kmutex_lock(&g_smscore_deviceslock); rc = smscore_notify_callbacks(coredev, coredev->device, 1); + smscore_init_ir(coredev); sms_info("device %p started, rc %d", coredev, rc); @@ -432,29 +506,19 @@ int smscore_start_device(struct smscore_device_t *coredev) } EXPORT_SYMBOL_GPL(smscore_start_device); -static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, - void *buffer, size_t size, - struct completion *completion) -{ - int rc = coredev->sendrequest_handler(coredev->context, buffer, size); - if (rc < 0) { - sms_info("sendrequest returned error %d", rc); - return rc; - } - - return wait_for_completion_timeout(completion, - msecs_to_jiffies(10000)) ? - 0 : -ETIME; -} static int smscore_load_firmware_family2(struct smscore_device_t *coredev, void *buffer, size_t size) { struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; struct SmsMsgHdr_ST *msg; - u32 mem_address = firmware->StartAddress; + u32 mem_address; u8 *payload = firmware->Payload; int rc = 0; + firmware->StartAddress = le32_to_cpu(firmware->StartAddress); + firmware->Length = le32_to_cpu(firmware->Length); + + mem_address = firmware->StartAddress; sms_info("loading FW to addr 0x%x size %d", mem_address, firmware->Length); @@ -621,6 +685,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev) kmutex_lock(&g_smscore_deviceslock); + /* Release input device (IR) resources */ + sms_ir_exit(coredev); + smscore_notify_clients(coredev); smscore_notify_callbacks(coredev, NULL, 0); @@ -628,7 +695,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev) * onresponse must no longer be called */ while (1) { - while ((cb = smscore_getbuffer(coredev))) { + while (!list_empty(&coredev->buffers)) { + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); kfree(cb); num_buffers++; } @@ -649,8 +718,10 @@ void smscore_unregister_device(struct smscore_device_t *coredev) if (coredev->common_buffer) dma_free_coherent(NULL, coredev->common_buffer_size, - coredev->common_buffer, - coredev->common_buffer_phys); + coredev->common_buffer, coredev->common_buffer_phys); + + if (coredev->fw_buf != NULL) + kfree(coredev->fw_buf); list_del(&coredev->entry); kfree(coredev); @@ -710,7 +781,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { /*BDA*/ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, /*ISDBT*/ - {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"}, + {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, /*ISDBTBDA*/ {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, /*CMMB*/ @@ -834,7 +905,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) coredev->device_flags &= ~SMS_DEVICE_NOT_READY; } - if (rc != 0) + if (rc < 0) sms_err("return error code %d.", rc); return rc; } @@ -904,15 +975,11 @@ smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, * */ void smscore_onresponse(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb) -{ - struct SmsMsgHdr_ST *phdr = - (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset); - struct smscore_client_t *client = - smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); + struct smscore_buffer_t *cb) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p + + cb->offset); + struct smscore_client_t *client; int rc = -EBUSY; - -#if 1 static unsigned long last_sample_time; /* = 0; */ static int data_total; /* = 0; */ unsigned long time_now = jiffies_to_msecs(jiffies); @@ -930,7 +997,16 @@ void smscore_onresponse(struct smscore_device_t *coredev, } data_total += cb->size; -#endif + /* Do we need to re-route? */ + if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || + (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { + if (coredev->mode == DEVICE_MODE_DVBT_BDA) + phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; + } + + + client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); + /* If no client registered for type & id, * check for control client where type is not registered */ if (client) @@ -975,6 +1051,18 @@ void smscore_onresponse(struct smscore_device_t *coredev, case MSG_SMS_SLEEP_RESUME_COMP_IND: complete(&coredev->resume_done); break; + case MSG_SMS_START_IR_RES: + complete(&coredev->ir_init_done); + break; + case MSG_SMS_IR_SAMPLES_IND: + sms_ir_event(coredev, + (const char *) + ((char *)phdr + + sizeof(struct SmsMsgHdr_ST)), + (int)phdr->msgLength + - sizeof(struct SmsMsgHdr_ST)); + break; + default: #if 0 sms_info("no client (%p) or error (%d), " @@ -1001,12 +1089,24 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev) struct smscore_buffer_t *cb = NULL; unsigned long flags; + DEFINE_WAIT(wait); + spin_lock_irqsave(&coredev->bufferslock, flags); - if (!list_empty(&coredev->buffers)) { - cb = (struct smscore_buffer_t *) coredev->buffers.next; - list_del(&cb->entry); - } + /* This function must return a valid buffer, since the buffer list is + * finite, we check that there is an available buffer, if not, we wait + * until such buffer become available. + */ + + prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE); + + if (list_empty(&coredev->buffers)) + schedule(); + + finish_wait(&coredev->buffer_mng_waitq, &wait); + + cb = (struct smscore_buffer_t *) coredev->buffers.next; + list_del(&cb->entry); spin_unlock_irqrestore(&coredev->bufferslock, flags); @@ -1023,8 +1123,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer); * */ void smscore_putbuffer(struct smscore_device_t *coredev, - struct smscore_buffer_t *cb) -{ + struct smscore_buffer_t *cb) { + wake_up_interruptible(&coredev->buffer_mng_waitq); list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock); } EXPORT_SYMBOL_GPL(smscore_putbuffer); diff --git a/linux/drivers/media/dvb/siano/smscoreapi.h b/linux/drivers/media/dvb/siano/smscoreapi.h index 83e0e55f7..f4aa406ef 100644 --- a/linux/drivers/media/dvb/siano/smscoreapi.h +++ b/linux/drivers/media/dvb/siano/smscoreapi.h @@ -1,26 +1,26 @@ -/* - * Driver for the Siano SMS1xxx USB dongle - * - * author: Anatoly Greenblat - * - * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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 __smscoreapi_h__ -#define __smscoreapi_h__ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat + +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, see <http://www.gnu.org/licenses/>. + +****************************************************************/ + +#ifndef __SMS_CORE_API_H__ +#define __SMS_CORE_API_H__ #include <linux/version.h> #include <linux/device.h> @@ -28,15 +28,14 @@ #include <linux/mm.h> #include <linux/scatterlist.h> #include <linux/types.h> -#include <asm/page.h> #include <linux/mutex.h> -#include "compat.h" +#include <linux/wait.h> +#include <linux/timer.h> -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" +#include <asm/page.h> +#include "compat.h" +#include "smsir.h" #define kmutex_init(_p_) mutex_init(_p_) #define kmutex_lock(_p_) mutex_lock(_p_) @@ -170,7 +169,7 @@ struct smscore_device_t { u32 fw_buf_size; /* Infrared (IR) */ - /* struct ir_t ir; */ + struct ir_t ir; int led_state; }; @@ -209,19 +208,15 @@ struct smscore_device_t { #define MSG_SMS_INIT_DEVICE_RES 579 #define MSG_SMS_ADD_PID_FILTER_REQ 601 #define MSG_SMS_ADD_PID_FILTER_RES 602 -#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 -#define MSG_SMS_REMOVE_PID_FILTER_RES 604 -#define MSG_SMS_DAB_CHANNEL 607 -#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 -#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 -#define MSG_SMS_GET_STATISTICS_REQ 615 -#define MSG_SMS_GET_STATISTICS_RES 616 +#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 +#define MSG_SMS_REMOVE_PID_FILTER_RES 604 +#define MSG_SMS_DAB_CHANNEL 607 +#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 +#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 #define MSG_SMS_HO_PER_SLICES_IND 630 -#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 -#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 -#define MSG_SMS_GET_STATISTICS_EX_REQ 653 -#define MSG_SMS_GET_STATISTICS_EX_RES 654 -#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 +#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 +#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 +#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 #define MSG_SMS_DATA_DOWNLOAD_REQ 660 #define MSG_SMS_DATA_DOWNLOAD_RES 661 #define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 @@ -343,225 +338,202 @@ struct SmsFirmware_ST { u8 Payload[1]; }; -struct SMSHOSTLIB_STATISTICS_ST { - u32 Reserved; /* Reserved */ +/* Statistics information returned as response for + * SmsHostApiGetStatistics_Req */ +struct SMSHOSTLIB_STATISTICS_S { + u32 Reserved; /* Reserved */ /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ /* Reception quality */ - s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ - u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ - /* Transport stream PER, 0xFFFFFFFF indicate N/A, - * valid only for DVB-T/H */ - u32 TS_PER; - /* DVB-H frame error rate in percentage, - * 0xFFFFFFFF indicate N/A, valid only for DVB-H */ - u32 MFER; - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - - /* Transmission parameters, valid only for DVB-T/H */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - /* Transmission Mode, for DAB modes 1-4, - * for DVB-T/H FFT mode carriers in Kilos */ - u32 TransmissionMode; - u32 ModemState; /* from SMS_DvbModemState_ET */ - u32 GuardInterval; /* Guard Interval, 1 divided by value */ - u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */ - u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */ - u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */ - u32 Constellation; /* Constellation from SMS_Constellation_ET */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ + u32 TS_PER; /* Transport stream PER, + 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ + u32 MFER; /* DVB-H frame error rate in percentage, + 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - /* Burst parameters, valid only for DVB-H */ - u32 BurstSize; /* Current burst size in bytes */ - u32 BurstDuration; /* Current burst duration in mSec */ - u32 BurstCycleTime; /* Current burst cycle time in mSec */ - u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec, - * as calculated by demodulator */ - u32 NumOfRows; /* Number of rows in MPE table */ - u32 NumOfPaddCols; /* Number of padding columns in MPE table */ - u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */ - /* Burst parameters */ - u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include - * errors after MPE RS decoding */ - u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors - * after MPE RS decoding */ - u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected - * by MPE RS decoding */ + /* Transmission parameters */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ + u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, + for DVB-T/H FFT mode carriers in Kilos */ + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, + valid only for DVB-T/H */ + u32 GuardInterval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + valid only for DVB-T/H */ + u32 LPCodeRate; /* Low Priority Code Rate from + SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ + u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, + valid only for DVB-T/H */ + u32 Constellation; /* Constellation from + SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ + /* Burst parameters, valid only for DVB-H */ + u32 BurstSize; /* Current burst size in bytes, + valid only for DVB-H */ + u32 BurstDuration; /* Current burst duration in mSec, + valid only for DVB-H */ + u32 BurstCycleTime; /* Current burst cycle time in mSec, + valid only for DVB-H */ + u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, + as calculated by demodulator, valid only for DVB-H */ + u32 NumOfRows; /* Number of rows in MPE table, + valid only for DVB-H */ + u32 NumOfPaddCols; /* Number of padding columns in MPE table, + valid only for DVB-H */ + u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, + valid only for DVB-H */ + u32 ErrorTSPackets; /* Number of erroneous + transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include + errors after MPE RS decoding */ + u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors + after MPE RS decoding */ + u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were + corrected by MPE RS decoding */ /* Common params */ - u32 BERErrorCount; /* Number of errornous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ + u32 BERErrorCount; /* Number of errornous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + u32 SmsToHostTxErrors; /* Total number of transmission errors. */ /* DAB/T-DMB */ - u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; - * if set to 0xFFFFFFFF cell_id not yet recovered */ - -}; + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + if set to 0xFFFFFFFF cell_id not yet recovered */ + u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ -struct SmsMsgStatisticsInfo_ST { - u32 RequestResult; - - struct SMSHOSTLIB_STATISTICS_ST Stat; - - /* Split the calc of the SNR in DAB */ - u32 Signal; /* dB */ - u32 Noise; /* dB */ + u32 NumMPEReceived; /* DVB-H, Num MPE section received */ + u32 ReservedFields[10]; /* Reserved */ }; -#if 0 -struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { - /* Per-layer information */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, - * 255 means layer does not exist */ - u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET, - * 255 means layer does not exist */ - u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 BERErrorCount; /* Post Viterbi Error Bits Count */ - u32 BERBitCount; /* Post Viterbi Total Bits Count */ - u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ - u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 TILdepthI; /* Time interleaver depth I parameter, - * 255 means layer does not exist */ - u32 NumberOfSegments; /* Number of segments in layer A, - * 255 means layer does not exist */ - u32 TMCCErrors; /* TMCC errors */ +struct PID_STATISTICS_DATA_S { + struct PID_BURST_S { + u32 size; + u32 padding_cols; + u32 punct_cols; + u32 duration; + u32 cycle; + u32 calc_cycle; + } burst; + + u32 tot_tbl_cnt; + u32 invalid_tbl_cnt; + u32 tot_cor_tbl; }; -struct SMSHOSTLIB_STATISTICS_ISDBT_ST { - u32 StatisticsType; /* Enumerator identifying the type of the - * structure. Values are the same as - * SMSHOSTLIB_DEVICE_MODES_E - * - * This field MUST always be first in any - * statistics structure */ - - u32 FullSize; /* Total size of the structure returned by the modem. - * If the size requested by the host is smaller than - * FullSize, the struct will be truncated */ - - /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ - - /* Reception quality */ - s32 SNR; /* dB */ - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in Hz */ - - /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* ISDB-T transmission mode */ - u32 ModemState; /* 0 - Acquisition, 1 - Locked */ - u32 GuardInterval; /* Guard Interval, 1 divided by value */ - u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ - u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ - u32 NumOfLayers; /* Number of ISDB-T layers in the network */ - - /* Per-layer information */ - /* Layers A, B and C */ - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; - /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ +struct PID_DATA_S { + u32 pid; + u32 num_rows; + struct PID_STATISTICS_DATA_S pid_statistics; +}; - /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ +#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) +#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) +#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ + if (_stat.TransmissionMode == 0) \ + _stat.TransmissionMode = 2; \ + else if (_stat.TransmissionMode == 1) \ + _stat.TransmissionMode = 8; \ + else \ + _stat.TransmissionMode = 4; + +struct TRANSMISSION_STATISTICS_S { + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* FFT mode carriers in Kilos */ + u32 GuardInterval; /* Guard Interval from + SMSHOSTLIB_GUARD_INTERVALS_ET */ + u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ + u32 LPCodeRate; /* Low Priority Code Rate from + SMSHOSTLIB_CODE_RATE_ET */ + u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ + u32 Constellation; /* Constellation from + SMSHOSTLIB_CONSTELLATION_ET */ + /* DVB-H TPS parameters */ + u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + if set to 0xFFFFFFFF cell_id not yet recovered */ + u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + Time Slicing indicator, bit 0 - MPE-FEC indicator */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ }; -struct SMSHOSTLIB_STATISTICS_DVB_ST { - u32 StatisticsType; /* Enumerator identifying the type of the - * structure. Values are the same as - * SMSHOSTLIB_DEVICE_MODES_E - * This field MUST always first in any - * statistics structure */ +struct RECEPTION_STATISTICS_S { + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 BERErrorCount; /* Number of erronous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + u32 TS_PER; /* Transport stream PER, + 0xFFFFFFFF indicate N/A */ + u32 MFER; /* DVB-H frame error rate in percentage, + 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + u32 ErrorTSPackets; /* Number of erroneous + transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + + s32 MRC_SNR; /* dB */ + s32 MRC_RSSI; /* dBm */ + s32 MRC_InBandPwr; /* In band power in dBM */ +}; - u32 FullSize; /* Total size of the structure returned by the modem. - * If the size requested by the host is smaller than - * FullSize, the struct will be truncated */ - /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ - /* Reception quality */ - s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ - u32 BERErrorCount; /* Number of errornous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ - u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A */ - u32 MFER; /* DVB-H frame error rate in percentage, - * 0xFFFFFFFF indicate N/A, valid only for DVB-H */ - s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ +/* Statistics information returned as response for + * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ +struct SMSHOSTLIB_STATISTICS_DVB_S { + /* Reception */ + struct RECEPTION_STATISTICS_S ReceptionData; /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ - u32 TransmissionMode; /* FFT mode carriers in Kilos */ - u32 GuardInterval; /* Guard Interval, 1 divided by value */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ - u32 LPCodeRate; /* Low Priority Code Rate from - * SMSHOSTLIB_CODE_RATE_ET */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ - u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET */ + struct TRANSMISSION_STATISTICS_S TransmissionData; /* Burst parameters, valid only for DVB-H */ - u32 BurstSize; /* Current burst size in bytes */ - u32 BurstDuration; /* Current burst duration in mSec */ - u32 BurstCycleTime; /* Current burst cycle time in mSec */ - u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec, - * as calculated by demodulator */ - u32 NumOfRows; /* Number of rows in MPE table */ - u32 NumOfPaddCols; /* Number of padding columns in MPE table */ - u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */ - - u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - - u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include - * errors after MPE RS decoding */ - u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include - * errors after MPE RS decoding */ - u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were - * corrected by MPE RS decoding */ - - u32 NumMPEReceived; /* DVB-H, Num MPE section received */ - - /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; - * if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, - * bit 1 - Time Slicing indicator, - * bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, - * bit 1 - Time Slicing indicator, - * bit 0 - MPE-FEC indicator */ - - /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ +#define SRVM_MAX_PID_FILTERS 8 + struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; +}; +struct SRVM_SIGNAL_STATUS_S { + u32 result; + u32 snr; + u32 tsPackets; + u32 etsPackets; + u32 constellation; + u32 hpCode; + u32 tpsSrvIndLP; + u32 tpsSrvIndHP; + u32 cellId; + u32 reason; + + s32 inBandPower; + u32 requestId; }; struct SMSHOSTLIB_I2C_REQ_ST { @@ -576,7 +548,7 @@ struct SMSHOSTLIB_I2C_RES_ST { u32 ReadCount; /* number of bytes read */ u8 Data[1]; }; -#endif + struct smscore_gpio_config { #define SMS_GPIO_DIRECTION_INPUT 0 @@ -679,4 +651,4 @@ int smscore_led_state(struct smscore_device_t *core, int led); dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) -#endif /* __smscoreapi_h__ */ +#endif /* __SMS_CORE_API_H__ */ diff --git a/linux/drivers/media/dvb/siano/smsdvb.c b/linux/drivers/media/dvb/siano/smsdvb.c index 035bd52c9..39421ee6f 100644 --- a/linux/drivers/media/dvb/siano/smsdvb.c +++ b/linux/drivers/media/dvb/siano/smsdvb.c @@ -1,28 +1,34 @@ -/* - * Driver for the Siano SMS1xxx USB dongle - * - * Author: Uri Shkolni - * - * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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. - */ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +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, see <http://www.gnu.org/licenses/>. + +****************************************************************/ #include <linux/module.h> #include <linux/init.h> +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + #include "smscoreapi.h" +#include "smsendian.h" #include "sms-cards.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -39,12 +45,15 @@ struct smsdvb_client_t { struct dvb_frontend frontend; fe_status_t fe_status; - int fe_ber, fe_snr, fe_unc, fe_signal_strength; - struct completion tune_done, stat_done; + struct completion tune_done; /* todo: save freq/band instead whole struct */ struct dvb_frontend_parameters fe_params; + + struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; + int event_fe_state; + int event_unc_state; }; static struct list_head g_smsdvb_clients; @@ -54,11 +63,21 @@ static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); +/* Events that may come from DVB v3 adapter */ +static void sms_board_dvb3_event(struct smsdvb_client_t *client, + enum SMS_DVB3_EVENTS event) { +} + static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) { struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; - struct SmsMsgHdr_ST *phdr = - (struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset); + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) + + cb->offset); + u32 *pMsgData = (u32 *) phdr + 1; + /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ + bool is_status_update = false; + + smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); switch (phdr->msgType) { case MSG_SMS_DVBT_BDA_DATA: @@ -70,43 +89,110 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) complete(&client->tune_done); break; - case MSG_SMS_GET_STATISTICS_RES: - { - struct SmsMsgStatisticsInfo_ST *p = - (struct SmsMsgStatisticsInfo_ST *)(phdr + 1); - - if (p->Stat.IsDemodLocked) { - client->fe_status = FE_HAS_SIGNAL | - FE_HAS_CARRIER | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_LOCK; - - client->fe_snr = p->Stat.SNR; - client->fe_ber = p->Stat.BER; - client->fe_unc = p->Stat.BERErrorCount; - - if (p->Stat.InBandPwr < -95) - client->fe_signal_strength = 0; - else if (p->Stat.InBandPwr > -29) - client->fe_signal_strength = 100; - else - client->fe_signal_strength = - (p->Stat.InBandPwr + 95) * 3 / 2; + case MSG_SMS_SIGNAL_DETECTED_IND: + sms_info("MSG_SMS_SIGNAL_DETECTED_IND"); + client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; + is_status_update = true; + break; + + case MSG_SMS_NO_SIGNAL_IND: + sms_info("MSG_SMS_NO_SIGNAL_IND"); + client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; + is_status_update = true; + break; + + case MSG_SMS_TRANSMISSION_IND: { + sms_info("MSG_SMS_TRANSMISSION_IND"); + + pMsgData++; + memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, + sizeof(struct TRANSMISSION_STATISTICS_S)); + + /* Mo need to correct guard interval + * (as opposed to old statistics message). + */ + CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); + CORRECT_STAT_TRANSMISSON_MODE( + client->sms_stat_dvb.TransmissionData); + is_status_update = true; + break; + } + case MSG_SMS_HO_PER_SLICES_IND: { + struct RECEPTION_STATISTICS_S *pReceptionData = + &client->sms_stat_dvb.ReceptionData; + struct SRVM_SIGNAL_STATUS_S SignalStatusData; + + /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/ + pMsgData++; + SignalStatusData.result = pMsgData[0]; + SignalStatusData.snr = pMsgData[1]; + SignalStatusData.inBandPower = (s32) pMsgData[2]; + SignalStatusData.tsPackets = pMsgData[3]; + SignalStatusData.etsPackets = pMsgData[4]; + SignalStatusData.constellation = pMsgData[5]; + SignalStatusData.hpCode = pMsgData[6]; + SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03; + SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03; + SignalStatusData.cellId = pMsgData[9] & 0xFFFF; + SignalStatusData.reason = pMsgData[10]; + SignalStatusData.requestId = pMsgData[11]; + pReceptionData->IsRfLocked = pMsgData[16]; + pReceptionData->IsDemodLocked = pMsgData[17]; + pReceptionData->ModemState = pMsgData[12]; + pReceptionData->SNR = pMsgData[1]; + pReceptionData->BER = pMsgData[13]; + pReceptionData->RSSI = pMsgData[14]; + CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData); + + pReceptionData->InBandPwr = (s32) pMsgData[2]; + pReceptionData->CarrierOffset = (s32) pMsgData[15]; + pReceptionData->TotalTSPackets = pMsgData[3]; + pReceptionData->ErrorTSPackets = pMsgData[4]; + + /* TS PER */ + if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets) + > 0) { + pReceptionData->TS_PER = (SignalStatusData.etsPackets + * 100) / (SignalStatusData.tsPackets + + SignalStatusData.etsPackets); } else { - client->fe_status = 0; - client->fe_snr = - client->fe_ber = - client->fe_unc = - client->fe_signal_strength = 0; + pReceptionData->TS_PER = 0; } - complete(&client->stat_done); - break; - } } + pReceptionData->BERBitCount = pMsgData[18]; + pReceptionData->BERErrorCount = pMsgData[19]; + pReceptionData->MRC_SNR = pMsgData[20]; + pReceptionData->MRC_InBandPwr = pMsgData[21]; + pReceptionData->MRC_RSSI = pMsgData[22]; + + is_status_update = true; + break; + } + } smscore_putbuffer(client->coredev, cb); + if (is_status_update) { + if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) { + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER + | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); + if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets + == 0) + sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); + else + sms_board_dvb3_event(client, + DVB3_EVENT_UNC_ERR); + + } else { + /*client->fe_status = + (phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ? + 0 : FE_HAS_SIGNAL;*/ + client->fe_status = 0; + sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); + } + } + return 0; } @@ -149,6 +235,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed) PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); PidMsg.msgData[0] = feed->pid; + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg)); } @@ -169,6 +256,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed) PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); PidMsg.msgData[0] = feed->pid; + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg)); } @@ -177,7 +265,10 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, void *buffer, size_t size, struct completion *completion) { - int rc = smsclient_sendrequest(client->smsclient, buffer, size); + int rc; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer); + rc = smsclient_sendrequest(client->smsclient, buffer, size); if (rc < 0) return rc; @@ -186,83 +277,61 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, 0 : -ETIME; } -static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) -{ - struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, - DVBT_BDA_CONTROL_MSG_ID, - HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 }; - int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->stat_done); - if (ret < 0) - return ret; - - if (client->fe_status & FE_HAS_LOCK) - sms_board_led_feedback(client->coredev, - (client->fe_unc == 0) ? - SMS_LED_HI : SMS_LED_LO); - else - sms_board_led_feedback(client->coredev, SMS_LED_OFF); - return ret; -} - static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) { - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - int rc = smsdvb_send_statistics_request(client); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *stat = client->fe_status; + *stat = client->fe_status; - return rc; + return 0; } static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - int rc = smsdvb_send_statistics_request(client); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *ber = client->fe_ber; + *ber = client->sms_stat_dvb.ReceptionData.BER; - return rc; + return 0; } static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - int rc = smsdvb_send_statistics_request(client); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *strength = client->fe_signal_strength; + if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95) + *strength = 0; + else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29) + *strength = 100; + else + *strength = + (client->sms_stat_dvb.ReceptionData.InBandPwr + + 95) * 3 / 2; - return rc; + return 0; } static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - int rc = smsdvb_send_statistics_request(client); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *snr = client->fe_snr; + *snr = client->sms_stat_dvb.ReceptionData.SNR; - return rc; + return 0; } static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - int rc = smsdvb_send_statistics_request(client); + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); - if (!rc) - *ucblocks = client->fe_unc; + *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets; - return rc; + return 0; } static int smsdvb_get_tune_settings(struct dvb_frontend *fe, @@ -286,12 +355,15 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe, struct SmsMsgHdr_ST Msg; u32 Data[3]; } Msg; - int ret; - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; + client->fe_status = FE_HAS_SIGNAL; + client->event_fe_state = -1; + client->event_unc_state = -1; + + Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msgDstId = HIF_TASK; + Msg.Msg.msgFlags = 0; + Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; Msg.Msg.msgLength = sizeof(Msg); Msg.Data[0] = fep->frequency; Msg.Data[2] = 12000000; @@ -310,24 +382,6 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe, default: return -EINVAL; } - /* Disable LNA, if any. An error is returned if no LNA is present */ - ret = sms_board_lna_control(client->coredev, 0); - if (ret == 0) { - fe_status_t status; - - /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - smsdvb_read_status(fe, &status); - - if (status & FE_HAS_LOCK) - return ret; - - /* previous tune didnt lock - enable LNA and tune again */ - sms_board_lna_control(client->coredev, 1); - } - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->tune_done); } @@ -352,8 +406,7 @@ static int smsdvb_init(struct dvb_frontend *fe) struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); - sms_board_power(client->coredev, 1); - + sms_board_dvb3_event(client, DVB3_EVENT_INIT); return 0; } @@ -362,8 +415,7 @@ static int smsdvb_sleep(struct dvb_frontend *fe) struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); - sms_board_led_feedback(client->coredev, SMS_LED_OFF); - sms_board_power(client->coredev, 0); + sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); return 0; } @@ -488,7 +540,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, client->coredev = coredev; init_completion(&client->tune_done); - init_completion(&client->stat_done); kmutex_lock(&g_smsdvb_clientslock); @@ -496,8 +547,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, kmutex_unlock(&g_smsdvb_clientslock); - sms_info("success"); + client->event_fe_state = -1; + client->event_unc_state = -1; + sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); + sms_info("success"); sms_board_setup(coredev); return 0; @@ -550,5 +604,5 @@ module_init(smsdvb_module_init); module_exit(smsdvb_module_exit); MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); -MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/siano/smsendian.c b/linux/drivers/media/dvb/siano/smsendian.c index d79aa0512..457b6d02e 100644 --- a/linux/drivers/media/dvb/siano/smsendian.c +++ b/linux/drivers/media/dvb/siano/smsendian.c @@ -49,6 +49,7 @@ void smsendian_handle_tx_message(void *buffer) } #endif /* __BIG_ENDIAN */ } +EXPORT_SYMBOL_GPL(smsendian_handle_tx_message); void smsendian_handle_rx_message(void *buffer) { @@ -86,6 +87,7 @@ void smsendian_handle_rx_message(void *buffer) } #endif /* __BIG_ENDIAN */ } +EXPORT_SYMBOL_GPL(smsendian_handle_rx_message); void smsendian_handle_message_header(void *msg) { @@ -97,4 +99,4 @@ void smsendian_handle_message_header(void *msg) phdr->msgFlags = le16_to_cpu(phdr->msgFlags); #endif /* __BIG_ENDIAN */ } - +EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff --git a/linux/drivers/media/dvb/siano/smsir.c b/linux/drivers/media/dvb/siano/smsir.c index a5f302c58..e3d776fee 100644 --- a/linux/drivers/media/dvb/siano/smsir.c +++ b/linux/drivers/media/dvb/siano/smsir.c @@ -99,7 +99,7 @@ static void sms_ir_rc5_event(struct smscore_device_t *coredev, bool toggle_changed; u16 keycode; - sms_info("IR RC5 word: address %d, command %d, toggle %d", + sms_log("IR RC5 word: address %d, command %d, toggle %d", addr, cmd, toggle); toggle_changed = ir_toggle != toggle; @@ -118,7 +118,7 @@ static void sms_ir_rc5_event(struct smscore_device_t *coredev, (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN)) return; /* accept only repeated volume, reject other keys */ - sms_info("kernel input keycode (from ir) %d", keycode); + sms_log("kernel input keycode (from ir) %d", keycode); input_report_key(coredev->ir.input_dev, keycode, 1); input_sync(coredev->ir.input_dev); @@ -147,7 +147,7 @@ static u32 ir_rc5_decode(unsigned int code) break; case 3: /* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/ - sms_info("bad code"); + sms_log("bad code"); return 0; } } @@ -175,7 +175,7 @@ static void sms_rc5_parse_word(struct smscore_device_t *coredev) RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j) rc5_word = ir_rc5_decode(rc5_word); - /* sms_info("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */ + /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */ sms_ir_rc5_event(coredev, RC5_TOGGLE(rc5_word), @@ -210,11 +210,11 @@ static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev, if (ir_pos == RC5_WORD_LEN) sms_rc5_parse_word(coredev); else if (ir_pos) /* timeout within a word */ - sms_info("IR error parsing a word"); + sms_log("IR error parsing a word"); ir_pos = 0; ir_word = 0; - /* sms_info("timeout %d", time); */ + /* sms_log("timeout %d", time); */ break; } /* The time is within the range of this number of bits */ @@ -236,7 +236,7 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len) int count = len>>2; samples = (s32 *)buf; -/* sms_info("IR buffer received, length = %d", count);*/ +/* sms_log("IR buffer received, length = %d", count);*/ for (i = 0; i < count; i++) if (ir_protocol == IR_RC5) @@ -248,7 +248,7 @@ int sms_ir_init(struct smscore_device_t *coredev) { struct input_dev *input_dev; - sms_info("Allocating input device"); + sms_log("Allocating input device"); input_dev = input_allocate_device(); if (!input_dev) { sms_err("Not enough memory"); @@ -261,11 +261,11 @@ int sms_ir_init(struct smscore_device_t *coredev) coredev->ir.keyboard_layout_map = keyboard_layout_maps[coredev->ir.ir_kb_type]. keyboard_layout_map; - sms_info("IR remote keyboard type is %d", coredev->ir.ir_kb_type); + sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type); coredev->ir.controller = 0; /* Todo: vega/nova SPI number */ coredev->ir.timeout = IR_DEFAULT_TIMEOUT; - sms_info("IR port %d, timeout %d ms", + sms_log("IR port %d, timeout %d ms", coredev->ir.controller, coredev->ir.timeout); snprintf(coredev->ir.name, @@ -280,7 +280,7 @@ int sms_ir_init(struct smscore_device_t *coredev) input_dev->evbit[0] = BIT_MASK(EV_KEY); input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); - sms_info("Input device (IR) %s is set for key events", input_dev->name); + sms_log("Input device (IR) %s is set for key events", input_dev->name); if (input_register_device(input_dev)) { sms_err("Failed to register device"); @@ -296,6 +296,6 @@ void sms_ir_exit(struct smscore_device_t *coredev) if (coredev->ir.input_dev) input_unregister_device(coredev->ir.input_dev); - sms_info(""); + sms_log(""); } diff --git a/linux/drivers/media/dvb/siano/smsusb.c b/linux/drivers/media/dvb/siano/smsusb.c index 67be79549..3bbbdb197 100644 --- a/linux/drivers/media/dvb/siano/smsusb.c +++ b/linux/drivers/media/dvb/siano/smsusb.c @@ -1,23 +1,23 @@ -/* - * Driver for the Siano SMS1xxx USB dongle - * - * author: Anatoly Greenblat - * - * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. - * - * 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. - */ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat + +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, see <http://www.gnu.org/licenses/>. + +****************************************************************/ #include <linux/kernel.h> #include <linux/init.h> @@ -26,6 +26,7 @@ #include "smscoreapi.h" #include "sms-cards.h" +#include "smsendian.h" static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); @@ -68,15 +69,16 @@ static void smsusb_onresponse(struct urb *urb, struct pt_regs *regs) struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context; struct smsusb_device_t *dev = surb->dev; - if (urb->status < 0) { - sms_err("error, urb status %d, %d bytes", + if (urb->status == -ESHUTDOWN) { + sms_err("error, urb status %d (-ESHUTDOWN), %d bytes", urb->status, urb->actual_length); return; } - if (urb->actual_length > 0) { - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p; + if ((urb->actual_length > 0) && (urb->status == 0)) { + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p; + smsendian_handle_message_header(phdr); if (urb->actual_length >= phdr->msgLength) { surb->cb->size = phdr->msgLength; @@ -113,7 +115,10 @@ static void smsusb_onresponse(struct urb *urb, struct pt_regs *regs) "msglen %d actual %d", phdr->msgLength, urb->actual_length); } - } + } else + sms_err("error, urb status %d, %d bytes", + urb->status, urb->actual_length); + exit_and_resubmit: smsusb_submit_urb(dev, surb); @@ -180,6 +185,7 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size) struct smsusb_device_t *dev = (struct smsusb_device_t *) context; int dummy; + smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buffer, size, &dummy, 1000); } @@ -337,8 +343,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) case SMS_VEGA: dev->buffer_size = USB2_BUFFER_SIZE; dev->response_alignment = - dev->udev->ep_in[1]->desc.wMaxPacketSize - - sizeof(struct SmsMsgHdr_ST); + le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - + sizeof(struct SmsMsgHdr_ST); params.flags |= SMS_DEVICE_FAMILY2; break; @@ -552,14 +558,14 @@ int smsusb_module_init(void) void smsusb_module_exit(void) { - sms_debug(""); /* Regular USB Cleanup */ usb_deregister(&smsusb_driver); + sms_info("end"); } module_init(smsusb_module_init); module_exit(smsusb_module_exit); -MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle"); +MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle"); MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)"); MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/ttpci/av7110_av.c b/linux/drivers/media/dvb/ttpci/av7110_av.c index e4d0900d5..538848141 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_av.c +++ b/linux/drivers/media/dvb/ttpci/av7110_av.c @@ -89,6 +89,7 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, struct dvb_demux_feed *feed); +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len); int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) @@ -192,8 +193,6 @@ int av7110_av_start_play(struct av7110 *av7110, int av) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; } - if (!ret) - ret = av7110->playing; return ret; } @@ -437,6 +436,45 @@ static void play_audio_cb(u8 *buf, int count, void *priv) aux_ring_buffer_write(&av7110->aout, buf, count); } + +#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096) + +static ssize_t ts_play(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + struct dvb_ringbuffer *rb; + u8 *kb; + unsigned long todo = count; + + dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count); + + rb = (type) ? &av7110->avout : &av7110->aout; + kb = av7110->kbuf[type]; + + if (!kb) + return -ENOBUFS; + + if (nonblock && !FREE_COND_TS) + return -EWOULDBLOCK; + + while (todo >= TS_SIZE) { + if (!FREE_COND_TS) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(rb->queue, FREE_COND_TS)) + return count - todo; + } + if (copy_from_user(kb, buf, TS_SIZE)) + return -EFAULT; + write_ts_to_decoder(av7110, type, kb, TS_SIZE); + todo -= TS_SIZE; + buf += TS_SIZE; + } + + return count - todo; +} + + #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) @@ -780,11 +818,37 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, } +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len) +{ + struct ipack *ipack = &av7110->ipack[type]; + + if (buf[1] & TRANS_ERROR) { + av7110_ipack_reset(ipack); + return -1; + } + + if (!(buf[3] & PAYLOAD)) + return -1; + + if (buf[1] & PAY_START) + av7110_ipack_flush(ipack); + + if (buf[3] & ADAPT_FIELD) { + len -= buf[4] + 1; + buf += buf[4] + 1; + if (!len) + return 0; + } + + av7110_ipack_instant_repack(buf + 4, len - 4, ipack); + return 0; +} + + int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) { struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = (struct av7110 *) demux->priv; - struct ipack *ipack = &av7110->ipack[feed->pes_type]; dprintk(2, "av7110:%p, \n", av7110); @@ -804,20 +868,7 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l return -1; } - if (!(buf[3] & 0x10)) /* no payload? */ - return -1; - if (buf[1] & 0x40) - av7110_ipack_flush(ipack); - - if (buf[3] & 0x20) { /* adaptation field? */ - len -= buf[4] + 1; - buf += buf[4] + 1; - if (!len) - return 0; - } - - av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]); - return 0; + return write_ts_to_decoder(av7110, feed->pes_type, buf, len); } @@ -916,6 +967,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf, { struct dvb_device *dvbdev = file->private_data; struct av7110 *av7110 = dvbdev->priv; + unsigned char c; dprintk(2, "av7110:%p, \n", av7110); @@ -925,7 +977,12 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf, if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) return -EPERM; - return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); + else + return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); } static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) @@ -952,6 +1009,7 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf, { struct dvb_device *dvbdev = file->private_data; struct av7110 *av7110 = dvbdev->priv; + unsigned char c; dprintk(2, "av7110:%p, \n", av7110); @@ -959,7 +1017,13 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf, printk(KERN_ERR "not audio source memory\n"); return -EPERM; } - return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); + + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); + else + return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); } static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; @@ -1062,7 +1126,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, if (ret) break; } - if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { if (av7110->playing == RP_AV) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); @@ -1122,20 +1185,16 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_SET_DISPLAY_FORMAT: { video_displayformat_t format = (video_displayformat_t) arg; - switch (format) { case VIDEO_PAN_SCAN: av7110->display_panscan = VID_PAN_SCAN_PREF; break; - case VIDEO_LETTER_BOX: av7110->display_panscan = VID_VC_AND_PS_PREF; break; - case VIDEO_CENTER_CUT_OUT: av7110->display_panscan = VID_CENTRE_CUT_PREF; break; - default: ret = -EINVAL; } @@ -1183,7 +1242,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_SLOWMOTION: if (av7110->playing&RP_VIDEO) { - ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); + if (av7110->trickmode != TRICK_SLOW) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); if (!ret) ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); } else { @@ -1207,7 +1267,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_CLEAR_BUFFER: dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); av7110_ipack_reset(&av7110->ipack[1]); - if (av7110->playing == RP_AV) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); @@ -1228,13 +1287,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, break; case VIDEO_SET_STREAMTYPE: - break; default: ret = -ENOIOCTLCMD; break; } + return ret; } @@ -1309,7 +1368,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, case AUDIO_CHANNEL_SELECT: av7110->audiostate.channel_select = (audio_channel_select_t) arg; - switch(av7110->audiostate.channel_select) { case AUDIO_STEREO: ret = audcom(av7110, AUDIO_CMD_STEREO); @@ -1320,7 +1378,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); } break; - case AUDIO_MONO_LEFT: ret = audcom(av7110, AUDIO_CMD_MONO_L); if (!ret) { @@ -1330,7 +1387,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); } break; - case AUDIO_MONO_RIGHT: ret = audcom(av7110, AUDIO_CMD_MONO_R); if (!ret) { @@ -1340,7 +1396,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); } break; - default: ret = -EINVAL; break; @@ -1366,21 +1421,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; - case AUDIO_SET_ID: + case AUDIO_SET_ID: break; + case AUDIO_SET_MIXER: { struct audio_mixer *amix = (struct audio_mixer *)parg; - ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); break; } + case AUDIO_SET_STREAMTYPE: break; + default: ret = -ENOIOCTLCMD; } + return ret; } diff --git a/linux/drivers/media/dvb/ttpci/av7110_v4l.c b/linux/drivers/media/dvb/ttpci/av7110_v4l.c index 2210cff73..ce64c6214 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/linux/drivers/media/dvb/ttpci/av7110_v4l.c @@ -458,7 +458,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); if (av7110->analog_tuner_flags) { - if (i->index < 0 || i->index >= 4) + if (i->index >= 4) return -EINVAL; } else { if (i->index != 0) diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c index 855fe74b6..8ea915227 100644 --- a/linux/drivers/media/dvb/ttpci/budget-av.c +++ b/linux/drivers/media/dvb/ttpci/budget-av.c @@ -1413,7 +1413,7 @@ static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); - if (i->index < 0 || i->index >= KNC1_INPUTS) + if (i->index >= KNC1_INPUTS) return -EINVAL; memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); return 0; diff --git a/linux/drivers/media/radio/radio-mr800.c b/linux/drivers/media/radio/radio-mr800.c index 93d5a7aa6..5ff444cee 100644 --- a/linux/drivers/media/radio/radio-mr800.c +++ b/linux/drivers/media/radio/radio-mr800.c @@ -64,6 +64,7 @@ #include <media/v4l2-ioctl.h> #include <linux/usb.h> #include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/mutex.h> #include "compat.h" /* driver and module definitions */ diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index 9d48da2fb..8de867d30 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -440,6 +440,24 @@ config VIDEO_ADV7175 To compile this driver as a module, choose M here: the module will be called adv7175. +config VIDEO_THS7303 + tristate "THS7303 Video Amplifier" + depends on I2C + help + Support for TI THS7303 video amplifier + + To compile this driver as a module, choose M here: the + module will be called ths7303. + +config VIDEO_ADV7343 + tristate "ADV7343 video encoder" + depends on I2C + help + Support for Analog Devices I2C bus based ADV7343 encoder. + + To compile this driver as a module, choose M here: the + module will be called adv7343. + comment "Video improvement chips" config VIDEO_UPD64031A @@ -694,7 +712,7 @@ config VIDEO_CAFE_CCIC config SOC_CAMERA tristate "SoC camera support" - depends on VIDEO_V4L2 && HAS_DMA + depends on VIDEO_V4L2 && HAS_DMA && I2C select VIDEOBUF_GEN help SoC Camera is a common API to several cameras, not connecting diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index 7aefac643..f7d9a4c6f 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -49,11 +49,13 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o +obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o obj-$(CONFIG_VIDEO_BT819) += bt819.o obj-$(CONFIG_VIDEO_BT856) += bt856.o obj-$(CONFIG_VIDEO_BT866) += bt866.o obj-$(CONFIG_VIDEO_KS0127) += ks0127.o +obj-$(CONFIG_VIDEO_THS7303) += ths7303.o obj-$(CONFIG_VIDEO_ZORAN) += zoran/ diff --git a/linux/drivers/media/video/adv7343.c b/linux/drivers/media/video/adv7343.c new file mode 100644 index 000000000..30f5caf5d --- /dev/null +++ b/linux/drivers/media/video/adv7343.c @@ -0,0 +1,534 @@ +/* + * adv7343 - ADV7343 Video Encoder Driver + * + * The encoder hardware does not support SECAM. + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/ctype.h> +#include <linux/i2c.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/videodev2.h> +#include <linux/uaccess.h> +#include <linux/version.h> + +#include <media/adv7343.h> +#include <media/v4l2-device.h> +#include <media/v4l2-chip-ident.h> + +#include "adv7343_regs.h" + +MODULE_DESCRIPTION("ADV7343 video encoder driver"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +struct adv7343_state { + struct v4l2_subdev sd; + u8 reg00; + u8 reg01; + u8 reg02; + u8 reg35; + u8 reg80; + u8 reg82; + int bright; + int hue; + int gain; + u32 output; + v4l2_std_id std; +}; + +static inline struct adv7343_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct adv7343_state, sd); +} + +static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static const u8 adv7343_init_reg_val[] = { + ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT, + ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT, + + ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT, + ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT, + ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT, + ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT, + ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT, + ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT, + ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT, + + ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT, + ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT, + ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT, + ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT, + ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT, + ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT, + ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT, + ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT, + + ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT, + ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT, + ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT, +}; + +/* + * 2^32 + * FSC(reg) = FSC (HZ) * -------- + * 27000000 + */ +static const struct adv7343_std_info stdinfo[] = { + { + /* FSC(Hz) = 3,579,545.45 Hz */ + SD_STD_NTSC, 569408542, V4L2_STD_NTSC, + }, { + /* FSC(Hz) = 3,575,611.00 Hz */ + SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M, + }, { + /* FSC(Hz) = 3,582,056.00 */ + SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60, + }, +}; + +static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7343_state *state = to_state(sd); + struct adv7343_std_info *std_info; + int output_idx, num_std; + char *fsc_ptr; + u8 reg, val; + int err = 0; + int i = 0; + + output_idx = state->output; + + std_info = (struct adv7343_std_info *)stdinfo; + num_std = ARRAY_SIZE(stdinfo); + + for (i = 0; i < num_std; i++) { + if (std_info[i].stdid & std) + break; + } + + if (i == num_std) { + v4l2_dbg(1, debug, sd, + "Invalid std or std is not supported: %llx\n", + (unsigned long long)std); + return -EINVAL; + } + + /* Set the standard */ + val = state->reg80 & (~(SD_STD_MASK)); + val |= std_info[i].standard_val3; + err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); + if (err < 0) + goto setstd_exit; + + state->reg80 = val; + + /* Configure the input mode register */ + val = state->reg01 & (~((u8) INPUT_MODE_MASK)); + val |= SD_INPUT_MODE; + err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val); + if (err < 0) + goto setstd_exit; + + state->reg01 = val; + + /* Program the sub carrier frequency registers */ + fsc_ptr = (unsigned char *)&std_info[i].fsc_val; + reg = ADV7343_FSC_REG0; + for (i = 0; i < 4; i++, reg++, fsc_ptr++) { + err = adv7343_write(sd, reg, *fsc_ptr); + if (err < 0) + goto setstd_exit; + } + + val = state->reg80; + + /* Filter settings */ + if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443)) + val &= 0x03; + else if (std & ~V4L2_STD_SECAM) + val |= 0x04; + + err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val); + if (err < 0) + goto setstd_exit; + + state->reg80 = val; + +setstd_exit: + if (err != 0) + v4l2_err(sd, "Error setting std, write failed\n"); + + return err; +} + +static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type) +{ + struct adv7343_state *state = to_state(sd); + unsigned char val; + int err = 0; + + if (output_type > ADV7343_SVIDEO_ID) { + v4l2_dbg(1, debug, sd, + "Invalid output type or output type not supported:%d\n", + output_type); + return -EINVAL; + } + + /* Enable Appropriate DAC */ + val = state->reg00 & 0x03; + + if (output_type == ADV7343_COMPOSITE_ID) + val |= ADV7343_COMPOSITE_POWER_VALUE; + else if (output_type == ADV7343_COMPONENT_ID) + val |= ADV7343_COMPONENT_POWER_VALUE; + else + val |= ADV7343_SVIDEO_POWER_VALUE; + + err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val); + if (err < 0) + goto setoutput_exit; + + state->reg00 = val; + + /* Enable YUV output */ + val = state->reg02 | YUV_OUTPUT_SELECT; + err = adv7343_write(sd, ADV7343_MODE_REG0, val); + if (err < 0) + goto setoutput_exit; + + state->reg02 = val; + + /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */ + val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI); + err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val); + if (err < 0) + goto setoutput_exit; + + state->reg82 = val; + + /* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to + * zero */ + val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI); + err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val); + if (err < 0) + goto setoutput_exit; + + state->reg35 = val; + +setoutput_exit: + if (err != 0) + v4l2_err(sd, "Error setting output, write failed\n"); + + return err; +} + +static int adv7343_log_status(struct v4l2_subdev *sd) +{ + struct adv7343_state *state = to_state(sd); + + v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std); + v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" : + ((state->output == 1) ? "Component" : "S-Video")); + return 0; +} + +static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN, + ADV7343_BRIGHTNESS_MAX, 1, + ADV7343_BRIGHTNESS_DEF); + case V4L2_CID_HUE: + return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN, + ADV7343_HUE_MAX, 1 , + ADV7343_HUE_DEF); + case V4L2_CID_GAIN: + return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN, + ADV7343_GAIN_MAX, 1, + ADV7343_GAIN_DEF); + default: + break; + } + + return 0; +} + +static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + if (ctrl->value < ADV7343_BRIGHTNESS_MIN || + ctrl->value > ADV7343_BRIGHTNESS_MAX) { + v4l2_dbg(1, debug, sd, + "invalid brightness settings %d\n", + ctrl->value); + return -ERANGE; + } + + state->bright = ctrl->value; + err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, + state->bright); + break; + + case V4L2_CID_HUE: + if (ctrl->value < ADV7343_HUE_MIN || + ctrl->value > ADV7343_HUE_MAX) { + v4l2_dbg(1, debug, sd, "invalid hue settings %d\n", + ctrl->value); + return -ERANGE; + } + + state->hue = ctrl->value; + err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue); + break; + + case V4L2_CID_GAIN: + if (ctrl->value < ADV7343_GAIN_MIN || + ctrl->value > ADV7343_GAIN_MAX) { + v4l2_dbg(1, debug, sd, "invalid gain settings %d\n", + ctrl->value); + return -ERANGE; + } + + if ((ctrl->value > POSITIVE_GAIN_MAX) && + (ctrl->value < NEGATIVE_GAIN_MIN)) { + v4l2_dbg(1, debug, sd, + "gain settings not within the specified range\n"); + return -ERANGE; + } + + state->gain = ctrl->value; + err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain); + break; + + default: + return -EINVAL; + } + + if (err < 0) + v4l2_err(sd, "Failed to set the encoder controls\n"); + + return err; +} + +static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct adv7343_state *state = to_state(sd); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = state->bright; + break; + + case V4L2_CID_HUE: + ctrl->value = state->hue; + break; + + case V4L2_CID_GAIN: + ctrl->value = state->gain; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int adv7343_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); +} + +static const struct v4l2_subdev_core_ops adv7343_core_ops = { + .log_status = adv7343_log_status, + .g_chip_ident = adv7343_g_chip_ident, + .g_ctrl = adv7343_g_ctrl, + .s_ctrl = adv7343_s_ctrl, + .queryctrl = adv7343_queryctrl, +}; + +static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + + if (state->std == std) + return 0; + + err = adv7343_setstd(sd, std); + if (!err) + state->std = std; + + return err; +} + +static int adv7343_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + + if (state->output == output) + return 0; + + err = adv7343_setoutput(sd, output); + if (!err) + state->output = output; + + return err; +} + +static const struct v4l2_subdev_video_ops adv7343_video_ops = { + .s_std_output = adv7343_s_std_output, + .s_routing = adv7343_s_routing, +}; + +static const struct v4l2_subdev_ops adv7343_ops = { + .core = &adv7343_core_ops, + .video = &adv7343_video_ops, +}; + +static int adv7343_initialize(struct v4l2_subdev *sd) +{ + struct adv7343_state *state = to_state(sd); + int err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) { + + err = adv7343_write(sd, adv7343_init_reg_val[i], + adv7343_init_reg_val[i+1]); + if (err) { + v4l2_err(sd, "Error initializing\n"); + return err; + } + } + + /* Configure for default video standard */ + err = adv7343_setoutput(sd, state->output); + if (err < 0) { + v4l2_err(sd, "Error setting output during init\n"); + return -EINVAL; + } + + err = adv7343_setstd(sd, state->std); + if (err < 0) { + v4l2_err(sd, "Error setting std during init\n"); + return -EINVAL; + } + + return err; +} + +static int adv7343_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adv7343_state *state; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + state->reg00 = 0x80; + state->reg01 = 0x00; + state->reg02 = 0x20; + state->reg35 = 0x00; + state->reg80 = ADV7343_SD_MODE_REG1_DEFAULT; + state->reg82 = ADV7343_SD_MODE_REG2_DEFAULT; + + state->output = ADV7343_COMPOSITE_ID; + state->std = V4L2_STD_NTSC; + + v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); + return adv7343_initialize(&state->sd); +} + +static int adv7343_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + + return 0; +} + +static const struct i2c_device_id adv7343_id[] = { + {"adv7343", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, adv7343_id); + +static struct i2c_driver adv7343_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv7343", + }, + .probe = adv7343_probe, + .remove = adv7343_remove, + .id_table = adv7343_id, +}; + +static __init int init_adv7343(void) +{ + return i2c_add_driver(&adv7343_driver); +} + +static __exit void exit_adv7343(void) +{ + i2c_del_driver(&adv7343_driver); +} + +module_init(init_adv7343); +module_exit(exit_adv7343); diff --git a/linux/drivers/media/video/adv7343_regs.h b/linux/drivers/media/video/adv7343_regs.h new file mode 100644 index 000000000..3431045b3 --- /dev/null +++ b/linux/drivers/media/video/adv7343_regs.h @@ -0,0 +1,185 @@ +/* + * ADV7343 encoder related structure and register definitions + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef ADV7343_REG_H +#define ADV7343_REGS_H + +struct adv7343_std_info { + u32 standard_val3; + u32 fsc_val; + v4l2_std_id stdid; +}; + +/* Register offset macros */ +#define ADV7343_POWER_MODE_REG (0x00) +#define ADV7343_MODE_SELECT_REG (0x01) +#define ADV7343_MODE_REG0 (0x02) + +#define ADV7343_DAC2_OUTPUT_LEVEL (0x0b) + +#define ADV7343_SOFT_RESET (0x17) + +#define ADV7343_HD_MODE_REG1 (0x30) +#define ADV7343_HD_MODE_REG2 (0x31) +#define ADV7343_HD_MODE_REG3 (0x32) +#define ADV7343_HD_MODE_REG4 (0x33) +#define ADV7343_HD_MODE_REG5 (0x34) +#define ADV7343_HD_MODE_REG6 (0x35) + +#define ADV7343_HD_MODE_REG7 (0x39) + +#define ADV7343_SD_MODE_REG1 (0x80) +#define ADV7343_SD_MODE_REG2 (0x82) +#define ADV7343_SD_MODE_REG3 (0x83) +#define ADV7343_SD_MODE_REG4 (0x84) +#define ADV7343_SD_MODE_REG5 (0x86) +#define ADV7343_SD_MODE_REG6 (0x87) +#define ADV7343_SD_MODE_REG7 (0x88) +#define ADV7343_SD_MODE_REG8 (0x89) + +#define ADV7343_FSC_REG0 (0x8C) +#define ADV7343_FSC_REG1 (0x8D) +#define ADV7343_FSC_REG2 (0x8E) +#define ADV7343_FSC_REG3 (0x8F) + +#define ADV7343_SD_CGMS_WSS0 (0x99) + +#define ADV7343_SD_HUE_REG (0xA0) +#define ADV7343_SD_BRIGHTNESS_WSS (0xA1) + +/* Default values for the registers */ +#define ADV7343_POWER_MODE_REG_DEFAULT (0x10) +#define ADV7343_HD_MODE_REG1_DEFAULT (0x3C) /* Changed Default + 720p EAVSAV code*/ +#define ADV7343_HD_MODE_REG2_DEFAULT (0x01) /* Changed Pixel data + valid */ +#define ADV7343_HD_MODE_REG3_DEFAULT (0x00) /* Color delay 0 clks */ +#define ADV7343_HD_MODE_REG4_DEFAULT (0xE8) /* Changed */ +#define ADV7343_HD_MODE_REG5_DEFAULT (0x08) +#define ADV7343_HD_MODE_REG6_DEFAULT (0x00) +#define ADV7343_HD_MODE_REG7_DEFAULT (0x00) +#define ADV7343_SD_MODE_REG8_DEFAULT (0x00) +#define ADV7343_SOFT_RESET_DEFAULT (0x02) +#define ADV7343_COMPOSITE_POWER_VALUE (0x80) +#define ADV7343_COMPONENT_POWER_VALUE (0x1C) +#define ADV7343_SVIDEO_POWER_VALUE (0x60) +#define ADV7343_SD_HUE_REG_DEFAULT (127) +#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT (0x03) + +#define ADV7343_SD_CGMS_WSS0_DEFAULT (0x10) + +#define ADV7343_SD_MODE_REG1_DEFAULT (0x00) +#define ADV7343_SD_MODE_REG2_DEFAULT (0xC9) +#define ADV7343_SD_MODE_REG3_DEFAULT (0x10) +#define ADV7343_SD_MODE_REG4_DEFAULT (0x01) +#define ADV7343_SD_MODE_REG5_DEFAULT (0x02) +#define ADV7343_SD_MODE_REG6_DEFAULT (0x0C) +#define ADV7343_SD_MODE_REG7_DEFAULT (0x04) +#define ADV7343_SD_MODE_REG8_DEFAULT (0x00) + +/* Bit masks for Mode Select Register */ +#define INPUT_MODE_MASK (0x70) +#define SD_INPUT_MODE (0x00) +#define HD_720P_INPUT_MODE (0x10) +#define HD_1080I_INPUT_MODE (0x10) + +/* Bit masks for Mode Register 0 */ +#define TEST_PATTERN_BLACK_BAR_EN (0x04) +#define YUV_OUTPUT_SELECT (0x20) +#define RGB_OUTPUT_SELECT (0xDF) + +/* Bit masks for DAC output levels */ +#define DAC_OUTPUT_LEVEL_MASK (0xFF) +#define POSITIVE_GAIN_MAX (0x40) +#define POSITIVE_GAIN_MIN (0x00) +#define NEGATIVE_GAIN_MAX (0xFF) +#define NEGATIVE_GAIN_MIN (0xC0) + +/* Bit masks for soft reset register */ +#define SOFT_RESET (0x02) + +/* Bit masks for HD Mode Register 1 */ +#define OUTPUT_STD_MASK (0x03) +#define OUTPUT_STD_SHIFT (0) +#define OUTPUT_STD_EIA0_2 (0x00) +#define OUTPUT_STD_EIA0_1 (0x01) +#define OUTPUT_STD_FULL (0x02) +#define EMBEDDED_SYNC (0x04) +#define EXTERNAL_SYNC (0xFB) +#define STD_MODE_SHIFT (3) +#define STD_MODE_MASK (0x1F) +#define STD_MODE_720P (0x05) +#define STD_MODE_720P_25 (0x08) +#define STD_MODE_720P_30 (0x07) +#define STD_MODE_720P_50 (0x06) +#define STD_MODE_1080I (0x0D) +#define STD_MODE_1080I_25fps (0x0E) +#define STD_MODE_1080P_24 (0x12) +#define STD_MODE_1080P_25 (0x10) +#define STD_MODE_1080P_30 (0x0F) +#define STD_MODE_525P (0x00) +#define STD_MODE_625P (0x03) + +/* Bit masks for SD Mode Register 1 */ +#define SD_STD_MASK (0x03) +#define SD_STD_NTSC (0x00) +#define SD_STD_PAL_BDGHI (0x01) +#define SD_STD_PAL_M (0x02) +#define SD_STD_PAL_N (0x03) +#define SD_LUMA_FLTR_MASK (0x7) +#define SD_LUMA_FLTR_SHIFT (0x2) +#define SD_CHROMA_FLTR_MASK (0x7) +#define SD_CHROMA_FLTR_SHIFT (0x5) + +/* Bit masks for SD Mode Register 2 */ +#define SD_PBPR_SSAF_EN (0x01) +#define SD_PBPR_SSAF_DI (0xFE) +#define SD_DAC_1_DI (0xFD) +#define SD_DAC_2_DI (0xFB) +#define SD_PEDESTAL_EN (0x08) +#define SD_PEDESTAL_DI (0xF7) +#define SD_SQUARE_PIXEL_EN (0x10) +#define SD_SQUARE_PIXEL_DI (0xEF) +#define SD_PIXEL_DATA_VALID (0x40) +#define SD_ACTIVE_EDGE_EN (0x80) +#define SD_ACTIVE_EDGE_DI (0x7F) + +/* Bit masks for HD Mode Register 6 */ +#define HD_RGB_INPUT_EN (0x02) +#define HD_RGB_INPUT_DI (0xFD) +#define HD_PBPR_SYNC_EN (0x04) +#define HD_PBPR_SYNC_DI (0xFB) +#define HD_DAC_SWAP_EN (0x08) +#define HD_DAC_SWAP_DI (0xF7) +#define HD_GAMMA_CURVE_A (0xEF) +#define HD_GAMMA_CURVE_B (0x10) +#define HD_GAMMA_EN (0x20) +#define HD_GAMMA_DI (0xDF) +#define HD_ADPT_FLTR_MODEB (0x40) +#define HD_ADPT_FLTR_MODEA (0xBF) +#define HD_ADPT_FLTR_EN (0x80) +#define HD_ADPT_FLTR_DI (0x7F) + +#define ADV7343_BRIGHTNESS_MAX (127) +#define ADV7343_BRIGHTNESS_MIN (0) +#define ADV7343_BRIGHTNESS_DEF (3) +#define ADV7343_HUE_MAX (255) +#define ADV7343_HUE_MIN (0) +#define ADV7343_HUE_DEF (127) +#define ADV7343_GAIN_MAX (255) +#define ADV7343_GAIN_MIN (0) +#define ADV7343_GAIN_DEF (0) + +#endif diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c index 053bbe8c8..830c4a933 100644 --- a/linux/drivers/media/video/au0828/au0828-cards.c +++ b/linux/drivers/media/video/au0828/au0828-cards.c @@ -136,9 +136,9 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg) /* Tuner Reset Command from xc5000 */ /* Drive the tuner into reset and out */ au0828_clear(dev, REG_001, 2); - mdelay(200); + mdelay(10); au0828_set(dev, REG_001, 2); - mdelay(50); + mdelay(10); return 0; } else { printk(KERN_ERR diff --git a/linux/drivers/media/video/au0828/au0828-video.c b/linux/drivers/media/video/au0828/au0828-video.c index 8bc0f0481..ef44aa831 100644 --- a/linux/drivers/media/video/au0828/au0828-video.c +++ b/linux/drivers/media/video/au0828/au0828-video.c @@ -834,6 +834,9 @@ static int au0828_v4l2_close(struct file *filp) au0828_uninit_isoc(dev); + /* Save some power by putting tuner to sleep */ + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby); + /* When close the device, set the usb intf0 into alt0 to free USB bandwidth */ ret = usb_set_interface(dev->usbdev, 0, 0); @@ -915,11 +918,6 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - dprintk(2, "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); - return rc; } diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index 622807b54..8d2075186 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -4198,7 +4198,6 @@ static struct video_device *vdev_init(struct bttv *btv, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &btv->c.v4l2_dev; vfd->release = video_device_release; vfd->debug = bttv_debug; diff --git a/linux/drivers/media/video/bt8xx/bttv-i2c.c b/linux/drivers/media/video/bt8xx/bttv-i2c.c index bf94551c3..31f2f07d9 100644 --- a/linux/drivers/media/video/bt8xx/bttv-i2c.c +++ b/linux/drivers/media/video/bt8xx/bttv-i2c.c @@ -405,6 +405,27 @@ int __devinit init_bttv_i2c(struct bttv *btv) } if (0 == btv->i2c_rc && i2c_scan) do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client); + + /* Instantiate the IR receiver device, if present */ + if (0 == btv->i2c_rc) { + struct i2c_board_info info; + /* The external IR receiver is at i2c address 0x34 (0x35 for + reads). Future Hauppauge cards will have an internal + receiver at 0x30 (0x31 for reads). In theory, both can be + fitted, and Hauppauge suggest an external overrides an + internal. + + That's why we probe 0x1a (~0x34) first. CB + */ + const unsigned short addr_list[] = { + 0x1a, 0x18, 0x4b, 0x64, 0x30, + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list); + } return btv->i2c_rc; } diff --git a/linux/drivers/media/video/cpia2/cpia2_v4l.c b/linux/drivers/media/video/cpia2/cpia2_v4l.c index d4099f531..0b4a8f309 100644 --- a/linux/drivers/media/video/cpia2/cpia2_v4l.c +++ b/linux/drivers/media/video/cpia2/cpia2_v4l.c @@ -1064,7 +1064,7 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam) switch(m->id) { case CPIA2_CID_FLICKER_MODE: - if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS) + if (m->index >= NUM_FLICKER_CONTROLS) return -EINVAL; strcpy(m->name, flicker_controls[m->index].name); @@ -1082,14 +1082,14 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam) maximum = i; } } - if(m->index < 0 || m->index > maximum) + if (m->index > maximum) return -EINVAL; strcpy(m->name, framerate_controls[m->index].name); break; } case CPIA2_CID_LIGHTS: - if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS) + if (m->index >= NUM_LIGHTS_CONTROLS) return -EINVAL; strcpy(m->name, lights_controls[m->index].name); diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 41997dd18..f42a97314 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -313,7 +313,7 @@ static void cx18_process_eeprom(struct cx18 *cx) CX18_INFO("Autodetected %s\n", cx->card_name); if (tv.tuner_type == TUNER_ABSENT) - CX18_ERR("tveeprom cannot autodetect tuner!"); + CX18_ERR("tveeprom cannot autodetect tuner!\n"); if (cx->options.tuner == -1) cx->options.tuner = tv.tuner_type; diff --git a/linux/drivers/media/video/cx231xx/cx231xx-cards.c b/linux/drivers/media/video/cx231xx/cx231xx-cards.c index af6169516..68f92da9e 100644 --- a/linux/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/linux/drivers/media/video/cx231xx/cx231xx-cards.c @@ -282,12 +282,12 @@ static void cx231xx_config_tuner(struct cx231xx *dev) } /* ----------------------------------------------------------------------- */ -void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir) +void cx231xx_register_i2c_ir(struct cx231xx *dev) { - if (disable_ir) { - ir->get_key = NULL; + if (disable_ir) return; - } + + /* REVISIT: instantiate IR device */ /* detect & configure */ switch (dev->model) { diff --git a/linux/drivers/media/video/cx231xx/cx231xx-i2c.c b/linux/drivers/media/video/cx231xx/cx231xx-i2c.c index d196fe666..e71005c59 100644 --- a/linux/drivers/media/video/cx231xx/cx231xx-i2c.c +++ b/linux/drivers/media/video/cx231xx/cx231xx-i2c.c @@ -424,34 +424,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } -/* - * attach_inform() - * gets called when a device attaches to the i2c bus - * does some basic configuration - */ -static int attach_inform(struct i2c_client *client) -{ - struct cx231xx_i2c *bus = i2c_get_adapdata(client->adapter); - struct cx231xx *dev = bus->dev; - - switch (client->addr << 1) { - case 0x8e: - { - struct IR_i2c *ir = i2c_get_clientdata(client); - dprintk1(1, "attach_inform: IR detected (%s).\n", - ir->phys); - cx231xx_set_ir(dev, ir); - break; - } - break; - - default: - break; - } - - return 0; -} - static struct i2c_algorithm cx231xx_algo = { .master_xfer = cx231xx_i2c_xfer, .functionality = functionality, @@ -465,7 +437,6 @@ static struct i2c_adapter cx231xx_adap_template = { .name = "cx231xx", .id = I2C_HW_B_CX231XX, .algo = &cx231xx_algo, - .client_register = attach_inform, }; static struct i2c_client cx231xx_client_template = { @@ -540,6 +511,9 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus) if (0 == bus->i2c_rc) { if (i2c_scan) cx231xx_do_i2c_scan(dev, &bus->i2c_client); + + /* Instantiate the IR receiver device, if present */ + cx231xx_register_i2c_ir(dev); } else cx231xx_warn("%s: i2c bus %d register FAILED\n", dev->name, bus->nr); diff --git a/linux/drivers/media/video/cx231xx/cx231xx-input.c b/linux/drivers/media/video/cx231xx/cx231xx-input.c index 04d954cca..3171b0177 100644 --- a/linux/drivers/media/video/cx231xx/cx231xx-input.c +++ b/linux/drivers/media/video/cx231xx/cx231xx-input.c @@ -37,7 +37,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define i2cdprintk(fmt, arg...) \ if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ } #define dprintk(fmt, arg...) \ diff --git a/linux/drivers/media/video/cx231xx/cx231xx.h b/linux/drivers/media/video/cx231xx/cx231xx.h index 21b4023dd..d3c05186e 100644 --- a/linux/drivers/media/video/cx231xx/cx231xx.h +++ b/linux/drivers/media/video/cx231xx/cx231xx.h @@ -747,7 +747,7 @@ extern void cx231xx_card_setup(struct cx231xx *dev); extern struct cx231xx_board cx231xx_boards[]; extern struct usb_device_id cx231xx_id_table[]; extern const unsigned int cx231xx_bcount; -void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir); +void cx231xx_register_i2c_ir(struct cx231xx *dev); int cx231xx_tuner_callback(void *ptr, int component, int command, int arg); /* Provided by cx231xx-input.c */ diff --git a/linux/drivers/media/video/cx23885/cimax2.c b/linux/drivers/media/video/cx23885/cimax2.c index 0e29f97f3..fed6d9f9f 100644 --- a/linux/drivers/media/video/cx23885/cimax2.c +++ b/linux/drivers/media/video/cx23885/cimax2.c @@ -320,7 +320,7 @@ static void netup_read_ci_status(struct work_struct *work) "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0], buf[32]); - if (buf[0] && 1) + if (buf[0] & 1) state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; else diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c index 574cdb385..9974d9a78 100644 --- a/linux/drivers/media/video/cx23885/cx23885-417.c +++ b/linux/drivers/media/video/cx23885/cx23885-417.c @@ -1749,7 +1749,6 @@ static struct video_device *cx23885_video_dev_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->parent = &pci->dev; diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index 28f305dfd..93176fe4b 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -182,6 +182,22 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR1270] = { + .name = "Hauppauge WinTV-HVR1270", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1275] = { + .name = "Hauppauge WinTV-HVR1275", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1255] = { + .name = "Hauppauge WinTV-HVR1255", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1210] = { + .name = "Hauppauge WinTV-HVR1210", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -281,6 +297,26 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x1b55, .subdevice = 0x2a2c, .card = CX23885_BOARD_NETUP_DUAL_DVBS2_CI, + }, { + .subvendor = 0x0070, + .subdevice = 0x2211, + .card = CX23885_BOARD_HAUPPAUGE_HVR1270, + }, { + .subvendor = 0x0070, + .subdevice = 0x2215, + .card = CX23885_BOARD_HAUPPAUGE_HVR1275, + }, { + .subvendor = 0x0070, + .subdevice = 0x2251, + .card = CX23885_BOARD_HAUPPAUGE_HVR1255, + }, { + .subvendor = 0x0070, + .subdevice = 0x2291, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { + .subvendor = 0x0070, + .subdevice = 0x2295, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -322,6 +358,42 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) /* Make sure we support the board model */ switch (tv.model) { + case 22001: + /* WinTV-HVR1270 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Blast */ + case 22009: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Blast */ + case 22011: + /* WinTV-HVR1270 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Recv */ + case 22019: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Recv */ + case 22021: + /* WinTV-HVR1275 (PCIe, Retail, half height) + * ATSC/QAM and basic analog, IR Recv */ + case 22029: + /* WinTV-HVR1210 (PCIe, Retail, half height) + * DVB-T and basic analog, IR Recv */ + case 22101: + /* WinTV-HVR1270 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Blast */ + case 22109: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Blast */ + case 22111: + /* WinTV-HVR1270 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Recv */ + case 22119: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Recv */ + case 22121: + /* WinTV-HVR1275 (PCIe, Retail, full height) + * ATSC/QAM and basic analog, IR Recv */ + case 22129: + /* WinTV-HVR1210 (PCIe, Retail, full height) + * DVB-T and basic analog, IR Recv */ case 71009: /* WinTV-HVR1200 (PCIe, Retail, full height) * DVB-T and basic analog */ @@ -620,6 +692,21 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* enable irq */ cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: + /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */ + /* GPIO-6 I2C Gate which can isolate the demod from the bus */ + /* GPIO-9 Demod reset */ + + /* Put the parts into reset and back */ + cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1); + cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5); + cx23885_gpio_clear(dev, GPIO_9); + mdelay(20); + cx23885_gpio_set(dev, GPIO_9); + break; } } @@ -632,6 +719,10 @@ int cx23885_ir_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1200: case CX23885_BOARD_HAUPPAUGE_HVR1400: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: /* FIXME: Implement me */ break; case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: @@ -667,6 +758,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1200: case CX23885_BOARD_HAUPPAUGE_HVR1700: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; @@ -724,6 +819,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1400: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1210: default: ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c index 48f777b99..6988361c9 100644 --- a/linux/drivers/media/video/cx23885/cx23885-core.c +++ b/linux/drivers/media/video/cx23885/cx23885-core.c @@ -1744,6 +1744,88 @@ out: return IRQ_RETVAL(handled); } +static inline int encoder_on_portb(struct cx23885_dev *dev) +{ + return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER; +} + +static inline int encoder_on_portc(struct cx23885_dev *dev) +{ + return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER; +} + +/* Mask represents 32 different GPIOs, GPIO's are split into multiple + * registers depending on the board configuration (and whether the + * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will + * be pushed into the correct hardware register, regardless of the + * physical location. Certain registers are shared so we sanity check + * and report errors if we think we're tampering with a GPIo that might + * be assigned to the encoder (and used for the host bus). + * + * GPIO 2 thru 0 - On the cx23885 bridge + * GPIO 18 thru 3 - On the cx23417 host bus interface + * GPIO 23 thru 19 - On the cx25840 a/v core + */ +void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask) +{ + if (mask & 0x7) + cx_set(GP0_IO, mask & 0x7); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Setting GPIO on encoder ports\n", + dev->name); + cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3); + } + + /* TODO: 23-19 */ + if (mask & 0x00f80000) + printk(KERN_INFO "%s: Unsupported\n", dev->name); +} + +void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) +{ + if (mask & 0x00000007) + cx_clear(GP0_IO, mask & 0x7); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Clearing GPIO moving on encoder ports\n", + dev->name); + cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3); + } + + /* TODO: 23-19 */ + if (mask & 0x00f80000) + printk(KERN_INFO "%s: Unsupported\n", dev->name); +} + +void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) +{ + if ((mask & 0x00000007) && asoutput) + cx_set(GP0_IO, (mask & 0x7) << 16); + else if ((mask & 0x00000007) && !asoutput) + cx_clear(GP0_IO, (mask & 0x7) << 16); + + if (mask & 0x0007fff8) { + if (encoder_on_portb(dev) || encoder_on_portc(dev)) + printk(KERN_ERR + "%s: Enabling GPIO on encoder ports\n", + dev->name); + } + + /* MC417_OEN is active low for output, write 1 for an input */ + if ((mask & 0x0007fff8) && asoutput) + cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3); + + else if ((mask & 0x0007fff8) && !asoutput) + cx_set(MC417_OEN, (mask & 0x7fff8) >> 3); + + /* TODO: 23-19 */ +} + static int __devinit cx23885_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index eb3293789..4efc7dee1 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -52,6 +52,7 @@ #include "cimax2.h" #include "netup-eeprom.h" #include "netup-init.h" +#include "lgdt3305.h" static unsigned int debug; @@ -124,7 +125,20 @@ static struct tda10048_config hauppauge_hvr1200_config = { .output_mode = TDA10048_SERIAL_OUTPUT, .fwbulkwritelen = TDA10048_BULKWRITE_200, .inversion = TDA10048_INVERSION_ON, - .if_freq_khz = TDA10048_IF_4300, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3800, + .dtv8_if_freq_khz = TDA10048_IF_4300, + .clk_freq_khz = TDA10048_CLK_16000, +}; + +static struct tda10048_config hauppauge_hvr1210_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_SERIAL_OUTPUT, + .fwbulkwritelen = TDA10048_BULKWRITE_200, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3500, + .dtv8_if_freq_khz = TDA10048_IF_4000, .clk_freq_khz = TDA10048_CLK_16000, }; @@ -197,6 +211,16 @@ static struct s5h1411_config dvico_s5h1411_config = { .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; +static struct s5h1411_config hcw_s5h1411_config = { + .output_mode = S5H1411_SERIAL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .vsb_if = S5H1411_IF_44000, + .qam_if = S5H1411_IF_4000, + .inversion = S5H1411_INVERSION_ON, + .status_mode = S5H1411_DEMODLOCKING, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, @@ -227,6 +251,32 @@ static struct tda18271_config hauppauge_hvr1200_tuner_config = { .gate = TDA18271_GATE_ANALOG, }; +static struct tda18271_config hauppauge_hvr1210_tuner_config = { + .gate = TDA18271_GATE_DIGITAL, +}; + +static struct tda18271_std_map hauppauge_hvr127x_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 hauppauge_hvr127x_config = { + .std_map = &hauppauge_hvr127x_std_map, +}; + +static struct lgdt3305_config hauppauge_lgdt3305_config = { + .i2c_addr = 0x0e, + .mpeg_mode = LGDT3305_MPEG_SERIAL, + .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, + .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, + .deny_i2c_rptr = 1, + .spectral_inversion = 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, +}; + static struct dibx000_agc_config xc3028_agc_config = { BAND_VHF | BAND_UHF, /* band_caps */ @@ -399,6 +449,29 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1270: + case CX23885_BOARD_HAUPPAUGE_HVR1275: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(lgdt3305_attach, + &hauppauge_lgdt3305_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_hvr127x_config); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1255: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1800: i2c_bus = &dev->i2c_bus[0]; switch (alt_tuner) { @@ -499,6 +572,17 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr1200_tuner_config); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1210: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(tda10048_attach, + &hauppauge_hvr1210_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_hvr1210_tuner_config); + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1400: i2c_bus = &dev->i2c_bus[0]; fe0->dvb.frontend = dvb_attach(dib7000p_attach, diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c index a5d9f7530..4369470a3 100644 --- a/linux/drivers/media/video/cx23885/cx23885-i2c.c +++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c @@ -364,6 +364,18 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", dev->name, bus->nr); + /* Instantiate the IR receiver device, if present */ + if (0 == bus->i2c_rc) { + struct i2c_board_info info; + const unsigned short addr_list[] = { + 0x6b, I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&bus->i2c_adap, &info, addr_list); + } + return bus->i2c_rc; } diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index 92828c9ce..8dba2fdd6 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -72,6 +72,21 @@ #define CX23885_BOARD_TEVII_S470 15 #define CX23885_BOARD_DVBWORLD_2005 16 #define CX23885_BOARD_NETUP_DUAL_DVBS2_CI 17 +#define CX23885_BOARD_HAUPPAUGE_HVR1270 18 +#define CX23885_BOARD_HAUPPAUGE_HVR1275 19 +#define CX23885_BOARD_HAUPPAUGE_HVR1255 20 +#define CX23885_BOARD_HAUPPAUGE_HVR1210 21 + +#define GPIO_0 0x00000001 +#define GPIO_1 0x00000002 +#define GPIO_2 0x00000004 +#define GPIO_3 0x00000008 +#define GPIO_4 0x00000010 +#define GPIO_5 0x00000020 +#define GPIO_6 0x00000040 +#define GPIO_7 0x00000080 +#define GPIO_8 0x00000100 +#define GPIO_9 0x00000200 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ #define CX23885_NORMS (\ @@ -423,6 +438,11 @@ extern int cx23885_restart_queue(struct cx23885_tsport *port, extern void cx23885_wakeup(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, u32 count); +extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); +extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); +extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, + int asoutput); + /* ----------------------------------------------------------- */ /* cx23885-cards.c */ diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index c9bfa835e..546793c02 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -2735,10 +2735,22 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core, switch (core->boardnr) { case CX88_BOARD_PINNACLE_PCTV_HD_800i: if (command == 0) { /* This is the reset command from xc5000 */ - /* Reset XC5000 tuner via SYS_RSTO_pin */ - cx_write(MO_SRST_IO, 0); - msleep(10); - cx_write(MO_SRST_IO, 1); + + /* djh - According to the engineer at PCTV Systems, + the xc5000 reset pin is supposed to be on GPIO12. + However, despite three nights of effort, pulling + that GPIO low didn't reset the xc5000. While + pulling MO_SRST_IO low does reset the xc5000, this + also resets in the s5h1409 being reset as well. + This causes tuning to always fail since the internal + state of the s5h1409 does not match the driver's + state. Given that the only two conditions in which + the driver performs a reset is during firmware load + and powering down the chip, I am taking out the + reset. We know that the chip is being reset + when the cx88 comes online, and not being able to + do power management for this board is worse than + not having any tuning at all. */ return 0; } else { err_printk(core, "xc5000: unknown tuner " diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c index 39cbd152a..fddba2d51 100644 --- a/linux/drivers/media/video/cx88/cx88-core.c +++ b/linux/drivers/media/video/cx88/cx88-core.c @@ -1057,7 +1057,6 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &core->v4l2_dev; vfd->parent = &pci->dev; vfd->release = video_device_release; diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c index 680a8c889..dbd629511 100644 --- a/linux/drivers/media/video/cx88/cx88-i2c.c +++ b/linux/drivers/media/video/cx88/cx88-i2c.c @@ -186,6 +186,19 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) do_i2c_scan(core->name,&core->i2c_client); } else printk("%s: i2c register FAILED\n", core->name); + + /* Instantiate the IR receiver device, if present */ + if (0 == core->i2c_rc) { + struct i2c_board_info info; + const unsigned short addr_list[] = { + 0x18, 0x6b, 0x71, + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&core->i2c_adap, &info, addr_list); + } return core->i2c_rc; } diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c index facb2e800..dad809335 100644 --- a/linux/drivers/media/video/cx88/cx88-input.c +++ b/linux/drivers/media/video/cx88/cx88-input.c @@ -92,6 +92,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) gpio=(gpio & 0x7fd) + (auxgpio & 0xef); break; case CX88_BOARD_WINFAST_DTV1000: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); auxgpio = gpio; break; @@ -244,6 +245,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) break; case CX88_BOARD_WINFAST2000XP_EXPERT: case CX88_BOARD_WINFAST_DTV1000: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c index 88a326f61..2dfa4c9c3 100644 --- a/linux/drivers/media/video/cx88/cx88-video.c +++ b/linux/drivers/media/video/cx88/cx88-video.c @@ -1152,8 +1152,10 @@ static int video_release(struct file *file) file->private_data = NULL; kfree(fh); + mutex_lock(&dev->core->lock); if(atomic_dec_and_test(&dev->core->users)) call_all(dev->core, tuner, s_standby); + mutex_unlock(&dev->core->lock); return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index fb83e4f6e..c765d769b 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -153,6 +153,16 @@ static struct em28xx_reg_seq compro_mute_gpio[] = { { -1, -1, -1, -1}, }; +/* Terratec AV350 */ +static struct em28xx_reg_seq terratec_av350_mute_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0x7f, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + { -1, -1, -1, -1}, +}; /* * Board definitions */ @@ -1412,6 +1422,42 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_VIDEO, } }, }, + [EM2860_BOARD_TERRATEC_GRABBY] = { + .name = "Terratec Grabby", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO2, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_VIDEO2, + } }, + }, + [EM2860_BOARD_TERRATEC_AV350] = { + .name = "Terratec AV350", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_TVP5150, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .mute_gpio = terratec_av350_mute_gpio, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AUDIO_SRC_LINE, + .gpio = terratec_av350_unmute_gpio, + + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AUDIO_SRC_LINE, + .gpio = terratec_av350_unmute_gpio, + } }, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1479,6 +1525,10 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2870_BOARD_TERRATEC_XS }, { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0x0ccd, 0x0084), + .driver_info = EM2860_BOARD_TERRATEC_AV350 }, + { USB_DEVICE(0x0ccd, 0x0096), + .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x185b, 0x2870), .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, { USB_DEVICE(0x185b, 0x2041), @@ -1931,12 +1981,20 @@ static int em28xx_hint_board(struct em28xx *dev) } /* ----------------------------------------------------------------------- */ -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) +void em28xx_register_i2c_ir(struct em28xx *dev) { - if (disable_ir) { - ir->get_key = NULL; - return ; - } + struct i2c_board_info info; + struct IR_i2c_init_data init_data; + const unsigned short addr_list[] = { + 0x30, 0x47, I2C_CLIENT_END + }; + + if (disable_ir) + return; + + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); /* detect & configure */ switch (dev->model) { @@ -1946,22 +2004,19 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) break; case (EM2800_BOARD_TERRATEC_CINERGY_200): case (EM2820_BOARD_TERRATEC_CINERGY_250): - ir->ir_codes = ir_codes_em_terratec; - ir->get_key = em28xx_get_key_terratec; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Terratec)"); + init_data.ir_codes = ir_codes_em_terratec; + init_data.get_key = em28xx_get_key_terratec; + init_data.name = "i2c IR (EM28XX Terratec)"; break; case (EM2820_BOARD_PINNACLE_USB_2): - ir->ir_codes = ir_codes_pinnacle_grey; - ir->get_key = em28xx_get_key_pinnacle_usb_grey; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Pinnacle PCTV)"); + init_data.ir_codes = ir_codes_pinnacle_grey; + init_data.get_key = em28xx_get_key_pinnacle_usb_grey; + init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; break; case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): - ir->ir_codes = ir_codes_hauppauge_new; - ir->get_key = em28xx_get_key_em_haup; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM2840 Hauppauge)"); + init_data.ir_codes = ir_codes_hauppauge_new; + init_data.get_key = em28xx_get_key_em_haup; + init_data.name = "i2c IR (EM2840 Hauppauge)"; break; case (EM2820_BOARD_MSI_VOX_USB_2): break; @@ -1972,6 +2027,10 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) case (EM2800_BOARD_GRABBEEX_USB2800): break; } + + if (init_data.name) + info.platform_data = &init_data; + i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); } void em28xx_card_setup(struct em28xx *dev) diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 401dc4e39..02e51af9d 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -1021,6 +1021,41 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, } EXPORT_SYMBOL_GPL(em28xx_init_isoc); +/* Determine the packet size for the DVB stream for the given device + (underlying value programmed into the eeprom) */ +int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) +{ + unsigned int chip_cfg2; + unsigned int packet_size = 564; + + if (dev->chip_id == CHIP_ID_EM2874) { + /* FIXME - for now assume 564 like it was before, but the + em2874 code should be added to return the proper value... */ + packet_size = 564; + } else { + /* TS max packet size stored in bits 1-0 of R01 */ + chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); + switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) { + case EM28XX_CHIPCFG2_TS_PACKETSIZE_188: + packet_size = 188; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_376: + packet_size = 376; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_564: + packet_size = 564; + break; + case EM28XX_CHIPCFG2_TS_PACKETSIZE_752: + packet_size = 752; + break; + } + } + + em28xx_coredbg("dvb max packet size=%d\n", packet_size); + return packet_size; +} +EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize); + /* * em28xx_wake_i2c() * configure i2c attached devices diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index dd749442d..de919504f 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -47,7 +47,6 @@ if (debug >= level) \ } while (0) #define EM28XX_DVB_NUM_BUFS 5 -#define EM28XX_DVB_MAX_PACKETSIZE 564 #define EM28XX_DVB_MAX_PACKETS 64 struct em28xx_dvb { @@ -143,14 +142,17 @@ static int start_streaming(struct em28xx_dvb *dvb) { int rc; struct em28xx *dev = dvb->adapter.priv; + int max_dvb_packet_size; usb_set_interface(dev->udev, 0, 1); rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; + max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev); + return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, - EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE, + EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, dvb_isoc_copy); } diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index 24456cebd..fd6be0e2c 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -451,27 +451,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -/* - * attach_inform() - * gets called when a device attaches to the i2c bus - * does some basic configuration - */ -static int attach_inform(struct i2c_client *client) -{ - struct em28xx *dev = client->adapter->algo_data; - struct IR_i2c *ir = i2c_get_clientdata(client); - - switch (client->addr << 1) { - case 0x60: - case 0x8e: - dprintk1(1, "attach_inform: IR detected (%s).\n", ir->phys); - em28xx_set_ir(dev, ir); - break; - } - - return 0; -} - static struct i2c_algorithm em28xx_algo = { .master_xfer = em28xx_i2c_xfer, .functionality = functionality, @@ -488,7 +467,6 @@ static struct i2c_adapter em28xx_adap_template = { .name = "em28xx", .id = I2C_HW_B_EM28XX, .algo = &em28xx_algo, - .client_register = attach_inform, }; static struct i2c_client em28xx_client_template = { @@ -581,6 +559,9 @@ int em28xx_i2c_register(struct em28xx *dev) if (i2c_scan) em28xx_do_i2c_scan(dev); + /* Instantiate the IR receiver device, if present */ + em28xx_register_i2c_ir(dev); + return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index 5382a6064..bfe2cb8f6 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define i2cdprintk(fmt, arg...) \ if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ } #define dprintk(fmt, arg...) \ @@ -86,7 +86,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)) { i2cdprintk("read error\n"); return -EIO; } @@ -115,7 +115,7 @@ 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 */ @@ -153,7 +153,7 @@ 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)) { i2cdprintk("read error\n"); return -EIO; } diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index 24e39c568..a2676d63c 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -27,6 +27,22 @@ #define EM28XX_CHIPCFG_AC97 0x10 #define EM28XX_CHIPCFG_AUDIOMASK 0x30 +#define EM28XX_R01_CHIPCFG2 0x01 + +/* em28xx Chip Configuration 2 0x01 */ +#define EM28XX_CHIPCFG2_TS_PRESENT 0x10 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK 0x0c /* bits 3-2 */ +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF 0x00 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF 0x04 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF 0x08 +#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF 0x0c +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK 0x03 /* bits 0-1 */ +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188 0x00 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376 0x01 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564 0x02 +#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03 + + /* GPIO/GPO registers */ #define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ #define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 966a3b924..e4ddc50c5 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -104,6 +104,8 @@ #define EM2860_BOARD_EASYCAP 64 #define EM2820_BOARD_IODATA_GVMVP_SZ 65 #define EM2880_BOARD_EMPIRE_DUAL_TV 66 +#define EM2860_BOARD_TERRATEC_GRABBY 67 +#define EM2860_BOARD_TERRATEC_AV350 68 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -625,6 +627,7 @@ 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_isoc_dvb_max_packetsize(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); void em28xx_wake_i2c(struct em28xx *dev); @@ -649,7 +652,7 @@ 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); +void em28xx_register_i2c_ir(struct em28xx *dev); int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_release_resources(struct em28xx *dev); diff --git a/linux/drivers/media/video/hexium_gemini.c b/linux/drivers/media/video/hexium_gemini.c index bcd8144c5..e7dc0aa61 100644 --- a/linux/drivers/media/video/hexium_gemini.c +++ b/linux/drivers/media/video/hexium_gemini.c @@ -225,7 +225,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - if (i->index < 0 || i->index >= HEXIUM_INPUTS) + if (i->index >= HEXIUM_INPUTS) return -EINVAL; memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); diff --git a/linux/drivers/media/video/hexium_orion.c b/linux/drivers/media/video/hexium_orion.c index 4178edcc2..d559c0e0c 100644 --- a/linux/drivers/media/video/hexium_orion.c +++ b/linux/drivers/media/video/hexium_orion.c @@ -326,7 +326,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - if (i->index < 0 || i->index >= HEXIUM_INPUTS) + if (i->index >= HEXIUM_INPUTS) return -EINVAL; memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c index 7bae57ad3..0a18d07c7 100644 --- a/linux/drivers/media/video/ir-kbd-i2c.c +++ b/linux/drivers/media/video/ir-kbd-i2c.c @@ -75,7 +75,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, int start, range, toggle, dev, code, ircode; /* poll IR chip */ - if (size != i2c_master_recv(&ir->c,buf,size)) + if (size != i2c_master_recv(ir->c, buf, size)) return -EIO; /* split rc5 data block ... */ @@ -138,7 +138,7 @@ static int get_key_pixelview(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(1,"read error\n"); return -EIO; } @@ -152,7 +152,7 @@ static int get_key_pv951(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(1,"read error\n"); return -EIO; } @@ -172,7 +172,7 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char buf[4]; /* poll IR chip */ - if (4 != i2c_master_recv(&ir->c,buf,4)) { + if (4 != i2c_master_recv(ir->c, buf, 4)) { dprintk(1,"read error\n"); return -EIO; } @@ -196,7 +196,7 @@ static int get_key_knc1(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(1,"read error\n"); return -EIO; } @@ -223,12 +223,12 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char subaddr, key, keygroup; - struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0, + struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1}, - { .addr = ir->c.addr, .flags = I2C_M_RD, + { .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &key, .len = 1} }; subaddr = 0x0d; - if (2 != i2c_transfer(ir->c.adapter, msg, 2)) { + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { dprintk(1, "read error\n"); return -EIO; } @@ -238,7 +238,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, subaddr = 0x0b; msg[1].buf = &keygroup; - if (2 != i2c_transfer(ir->c.adapter, msg, 2)) { + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { dprintk(1, "read error\n"); return -EIO; } @@ -295,7 +295,7 @@ static void ir_work(struct work_struct *work) /* MSI TV@nywhere Plus requires more frequent polling otherwise it will miss some keypresses */ - if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30) + if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30) polling_interval = 50; ir_key_poll(ir); @@ -304,34 +304,15 @@ static void ir_work(struct work_struct *work) /* ----------------------------------------------------------------------- */ -static int ir_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind); -static int ir_detach(struct i2c_client *client); -static int ir_probe(struct i2c_adapter *adap); - -static struct i2c_driver driver = { - .driver = { - .name = "ir-kbd-i2c", - }, - .id = I2C_DRIVERID_INFRARED, - .attach_adapter = ir_probe, - .detach_client = ir_detach, -}; - -static struct i2c_client client_template = -{ - .name = "unset", - .driver = &driver -}; - -static int ir_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) +static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { IR_KEYTAB_TYPE *ir_codes = NULL; - char *name; + const char *name = NULL; int ir_type; struct IR_i2c *ir; struct input_dev *input_dev; + struct i2c_adapter *adap = client->adapter; + unsigned short addr = client->addr; int err; ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL); @@ -341,13 +322,9 @@ static int ir_attach(struct i2c_adapter *adap, int addr, goto err_out_free; } - ir->c = client_template; + ir->c = client; ir->input = input_dev; - - ir->c.adapter = adap; - ir->c.addr = addr; - - i2c_set_clientdata(&ir->c, ir); + i2c_set_clientdata(client, ir); switch(addr) { case 0x64: @@ -412,44 +389,46 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_codes = ir_codes_avermedia_cardbus; break; default: - /* shouldn't happen */ - printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr); + dprintk(1, DEVNAME ": Unsupported i2c address 0x%02x\n", addr); err = -ENODEV; goto err_out_free; } - /* Sets name */ - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name); - ir->ir_codes = ir_codes; + /* Let the caller override settings */ + if (client->dev.platform_data) { + const struct IR_i2c_init_data *init_data = + client->dev.platform_data; - /* register i2c device - * At device register, IR codes may be changed to be - * board dependent. - */ - err = i2c_attach_client(&ir->c); - if (err) - goto err_out_free; + ir_codes = init_data->ir_codes; + name = init_data->name; + ir->get_key = init_data->get_key; + } - /* If IR not supported or disabled, unregisters driver */ - if (ir->get_key == NULL) { + /* Make sure we are all setup before going on */ + if (!name || !ir->get_key || !ir_codes) { + dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n", + addr); err = -ENODEV; - goto err_out_detach; + goto err_out_free; } - /* Phys addr can only be set after attaching (for ir->c.dev) */ + /* Sets name */ + snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); + ir->ir_codes = ir_codes; + snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", - dev_name(&ir->c.adapter->dev), - dev_name(&ir->c.dev)); + dev_name(&adap->dev), + dev_name(&client->dev)); /* init + register input device */ ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes); input_dev->id.bustype = BUS_I2C; - input_dev->name = ir->c.name; + input_dev->name = ir->name; input_dev->phys = ir->phys; err = input_register_device(ir->input); if (err) - goto err_out_detach; + goto err_out_free; printk(DEVNAME ": %s detected at %s [%s]\n", ir->input->name, ir->input->phys, adap->name); @@ -464,135 +443,42 @@ static int ir_attach(struct i2c_adapter *adap, int addr, return 0; - err_out_detach: - i2c_detach_client(&ir->c); err_out_free: input_free_device(input_dev); kfree(ir); return err; } -static int ir_detach(struct i2c_client *client) +static int ir_remove(struct i2c_client *client) { struct IR_i2c *ir = i2c_get_clientdata(client); /* kill outstanding polls */ cancel_delayed_work_sync(&ir->work); - /* unregister devices */ + /* unregister device */ input_unregister_device(ir->input); - i2c_detach_client(&ir->c); /* free memory */ kfree(ir); return 0; } -static int ir_probe(struct i2c_adapter *adap) -{ - - /* The external IR receiver is at i2c address 0x34 (0x35 for - reads). Future Hauppauge cards will have an internal - receiver at 0x30 (0x31 for reads). In theory, both can be - fitted, and Hauppauge suggest an external overrides an - internal. - - That's why we probe 0x1a (~0x34) first. CB - */ - - static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; - static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 }; - static const int probe_em28XX[] = { 0x30, 0x47, -1 }; - static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; - static const int probe_cx23885[] = { 0x6b, -1 }; - const int *probe; - struct i2c_msg msg = { - .flags = I2C_M_RD, - .len = 0, - .buf = NULL, - }; - int i, rc; - - switch (adap->id) { - case I2C_HW_B_BT848: - probe = probe_bttv; - break; - case I2C_HW_B_CX2341X: - probe = probe_bttv; - break; - case I2C_HW_SAA7134: - probe = probe_saa7134; - break; - case I2C_HW_B_EM28XX: - probe = probe_em28XX; - break; - case I2C_HW_B_CX2388x: - probe = probe_cx88; - break; - case I2C_HW_B_CX23885: - probe = probe_cx23885; - break; - default: - return 0; - } - - for (i = 0; -1 != probe[i]; i++) { - msg.addr = probe[i]; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1,"probe 0x%02x @ %s: %s\n", - probe[i], adap->name, - (1 == rc) ? "yes" : "no"); - if (1 == rc) { - ir_attach(adap, probe[i], 0, 0); - return 0; - } - } - - /* Special case for MSI TV@nywhere Plus remote */ - if (adap->id == I2C_HW_SAA7134) { - u8 temp; - - /* MSI TV@nywhere Plus controller doesn't seem to - respond to probes unless we read something from - an existing device. Weird... */ - - msg.addr = 0x50; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1, "probe 0x%02x @ %s: %s\n", - msg.addr, adap->name, - (1 == rc) ? "yes" : "no"); - - /* Now do the probe. The controller does not respond - to 0-byte reads, so we use a 1-byte read instead. */ - msg.addr = 0x30; - msg.len = 1; - msg.buf = &temp; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1, "probe 0x%02x @ %s: %s\n", - msg.addr, adap->name, - (1 == rc) ? "yes" : "no"); - if (1 == rc) - ir_attach(adap, msg.addr, 0, 0); - } - - /* Special case for AVerMedia Cardbus remote */ - if (adap->id == I2C_HW_SAA7134) { - unsigned char subaddr, data; - struct i2c_msg msg[] = { { .addr = 0x40, .flags = 0, - .buf = &subaddr, .len = 1}, - { .addr = 0x40, .flags = I2C_M_RD, - .buf = &data, .len = 1} }; - subaddr = 0x0d; - rc = i2c_transfer(adap, msg, 2); - dprintk(1, "probe 0x%02x/0x%02x @ %s: %s\n", - msg[0].addr, subaddr, adap->name, - (2 == rc) ? "yes" : "no"); - if (2 == rc) - ir_attach(adap, msg[0].addr, 0, 0); - } +static const struct i2c_device_id ir_kbd_id[] = { + /* Generic entry for any IR receiver */ + { "ir_video", 0 }, + /* IR device specific entries could be added here */ + { } +}; - return 0; -} +static struct i2c_driver driver = { + .driver = { + .name = "ir-kbd-i2c", + }, + .probe = ir_probe, + .remove = ir_remove, + .id_table = ir_kbd_id, +}; /* ----------------------------------------------------------------------- */ diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c index 984c73b5e..0d18c2220 100644 --- a/linux/drivers/media/video/ivtv/ivtv-i2c.c +++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c @@ -592,9 +592,11 @@ static struct i2c_client ivtv_i2c_client_template = { .name = "ivtv internal", }; -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter + instantiate IR receiver */ int init_ivtv_i2c(struct ivtv *itv) { + int retval; + IVTV_DEBUG_I2C("i2c init\n"); /* Sanity checks for the I2C hardware arrays. They must be the @@ -634,9 +636,37 @@ int init_ivtv_i2c(struct ivtv *itv) ivtv_setsda(itv, 1); if (itv->options.newi2c > 0) - return i2c_add_adapter(&itv->i2c_adap); + retval = i2c_add_adapter(&itv->i2c_adap); else - return i2c_bit_add_bus(&itv->i2c_adap); + retval = i2c_bit_add_bus(&itv->i2c_adap); + + /* Instantiate the IR receiver device, if present */ + if (retval == 0) { + struct i2c_board_info info; + /* The external IR receiver is at i2c address 0x34 (0x35 for + reads). Future Hauppauge cards will have an internal + receiver at 0x30 (0x31 for reads). In theory, both can be + fitted, and Hauppauge suggest an external overrides an + internal. + + That's why we probe 0x1a (~0x34) first. CB + */ + const unsigned short addr_list[] = { + 0x1a, /* Hauppauge IR external */ + 0x18, /* Hauppauge IR internal */ + 0x71, /* Hauppauge IR (PVR150) */ + 0x64, /* Pixelview IR */ + 0x30, /* KNC ONE IR */ + 0x6b, /* Adaptec IR */ + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&itv->i2c_adap, &info, addr_list); + } + + return retval; } void exit_ivtv_i2c(struct ivtv *itv) diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index c342a9fe9..99f3c39a1 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -709,7 +709,7 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; - else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE) + else if (regs->reg < IVTV_ENCODER_SIZE) reg_start = itv->enc_mem; else return -EINVAL; diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c index 4a50c0e95..411efcd34 100644 --- a/linux/drivers/media/video/mxb.c +++ b/linux/drivers/media/video/mxb.c @@ -457,7 +457,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) { DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - if (i->index < 0 || i->index >= MXB_INPUTS) + if (i->index >= MXB_INPUTS) return -EINVAL; memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); return 0; @@ -620,7 +620,7 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; - if (a->index < 0 || a->index > MXB_INPUTS) { + if (a->index > MXB_INPUTS) { DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); return -EINVAL; } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 129de13da..336a20ede 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -71,6 +71,7 @@ static const struct pvr2_device_desc pvr2_device_29xxx = { .flag_has_svideo = !0, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_29XXX, }; @@ -284,7 +285,9 @@ static struct tda10048_config hauppauge_tda10048_config = { .output_mode = TDA10048_PARALLEL_OUTPUT, .fwbulkwritelen = TDA10048_BULKWRITE_50, .inversion = TDA10048_INVERSION_ON, - .if_freq_khz = TDA10048_IF_4300, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3800, + .dtv8_if_freq_khz = TDA10048_IF_4300, .clk_freq_khz = TDA10048_CLK_16000, .disable_gate_access = 1, }; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h index 3e553389c..ea04ecf8a 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -69,6 +69,7 @@ struct pvr2_string_table { #define PVR2_ROUTING_SCHEME_HAUPPAUGE 0 #define PVR2_ROUTING_SCHEME_GOTVIEW 1 #define PVR2_ROUTING_SCHEME_ONAIR 2 +#define PVR2_ROUTING_SCHEME_AV400 3 #define PVR2_DIGITAL_SCHEME_NONE 0 #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1 @@ -78,8 +79,10 @@ struct pvr2_string_table { #define PVR2_LED_SCHEME_HAUPPAUGE 1 #define PVR2_IR_SCHEME_NONE 0 -#define PVR2_IR_SCHEME_24XXX 1 -#define PVR2_IR_SCHEME_ZILOG 2 +#define PVR2_IR_SCHEME_24XXX 1 /* FX2-controlled IR */ +#define PVR2_IR_SCHEME_ZILOG 2 /* HVR-1950 style (must be taken out of reset) */ +#define PVR2_IR_SCHEME_24XXX_MCE 3 /* 24xxx MCE device */ +#define PVR2_IR_SCHEME_29XXX 4 /* Original 29xxx device */ /* This describes a particular hardware type (except for the USB device ID which must live in a separate structure due to environmental @@ -162,19 +165,9 @@ struct pvr2_device_desc { ensure that it is found. */ unsigned int flag_has_wm8775:1; - /* Indicate any specialized IR scheme that might need to be - supported by this driver. If not set, then it is assumed that - IR can work without help from the driver (which is frequently - the case). This is otherwise set to one of - PVR2_IR_SCHEME_xxxx. For "xxxx", the value "24XXX" indicates a - Hauppauge 24xxx class device which has an FPGA-hosted IR - receiver that can only be reached via FX2 command codes. In - that case the pvrusb2 driver will emulate the behavior of the - older 29xxx device's IR receiver (a "virtual" I2C chip) in terms - of those command codes. For the value "ZILOG", we're dealing - with an IR chip that must be taken out of reset via another FX2 - command code (which is the case for HVR-1950 devices). */ - unsigned int ir_scheme:2; + /* Indicate IR scheme of hardware. If not set, then it is assumed + that IR can work without any help from the driver. */ + unsigned int ir_scheme:3; /* These bits define which kinds of sources the device can handle. Note: Digital tuner presence is inferred by the diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 5d75eb521..5b152ff20 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -200,6 +200,9 @@ struct pvr2_hdw { int i2c_cx25840_hack_state; int i2c_linked; + /* IR related */ + unsigned int ir_scheme_active; /* IR scheme as seen from the outside */ + /* Frequency table */ unsigned int freqTable[FREQTABLE_SIZE]; unsigned int freqProgSlot; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index c0e1e2cc9..3411cb36a 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -143,6 +143,15 @@ static const unsigned char *module_i2c_addresses[] = { }; +static const char *ir_scheme_names[] = { + [PVR2_IR_SCHEME_NONE] = "none", + [PVR2_IR_SCHEME_29XXX] = "29xxx", + [PVR2_IR_SCHEME_24XXX] = "24xxx (29xxx emulation)", + [PVR2_IR_SCHEME_24XXX_MCE] = "24xxx (MCE device)", + [PVR2_IR_SCHEME_ZILOG] = "Zilog", +}; + + /* Define the list of additional controls we'll dynamically construct based on query of the cx2341x module. */ struct pvr2_mpeg_ids { @@ -2187,7 +2196,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } /* Take the IR chip out of reset, if appropriate */ - if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_ZILOG) { + if (hdw->ir_scheme_active == PVR2_IR_SCHEME_ZILOG) { pvr2_issue_simple_cmd(hdw, FX2CMD_HCW_ZILOG_RESET | (1 << 8) | @@ -2468,6 +2477,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, GFP_KERNEL); if (!hdw->controls) goto fail; hdw->hdw_desc = hdw_desc; + hdw->ir_scheme_active = hdw->hdw_desc->ir_scheme; for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; cptr->hdw = hdw; @@ -4903,6 +4913,12 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, stats.buffers_processed, stats.buffers_failed); } + case 6: { + unsigned int id = hdw->ir_scheme_active; + return scnprintf(buf, acnt, "ir scheme: id=%d %s", id, + (id >= ARRAY_SIZE(ir_scheme_names) ? + "?" : ir_scheme_names[id])); + } default: break; } return 0; @@ -4919,65 +4935,35 @@ static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw, unsigned int tcnt = 0; unsigned int ccnt; struct i2c_client *client; - struct list_head *item; - void *cd; const char *p; unsigned int id; - ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:"); + ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers and I2C clients:\n"); tcnt += ccnt; v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { id = sd->grp_id; p = NULL; if (id < ARRAY_SIZE(module_names)) p = module_names[id]; if (p) { - ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p); + ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s:", p); tcnt += ccnt; } else { ccnt = scnprintf(buf + tcnt, acnt - tcnt, - " (unknown id=%u)", id); + " (unknown id=%u):", id); tcnt += ccnt; } - } - ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n"); - tcnt += ccnt; - - ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n"); - tcnt += ccnt; - - mutex_lock(&hdw->i2c_adap.clist_lock); - list_for_each(item, &hdw->i2c_adap.clients) { - client = list_entry(item, struct i2c_client, list); - ccnt = scnprintf(buf + tcnt, acnt - tcnt, - " %s: i2c=%02x", client->name, client->addr); - tcnt += ccnt; - cd = i2c_get_clientdata(client); - v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { - if (cd == sd) { - id = sd->grp_id; - p = NULL; - if (id < ARRAY_SIZE(module_names)) { - p = module_names[id]; - } - if (p) { - ccnt = scnprintf(buf + tcnt, - acnt - tcnt, - " subdev=%s", p); - tcnt += ccnt; - } else { - ccnt = scnprintf(buf + tcnt, - acnt - tcnt, - " subdev= id %u)", - id); - tcnt += ccnt; - } - break; - } + client = v4l2_get_subdevdata(sd); + if (client) { + ccnt = scnprintf(buf + tcnt, acnt - tcnt, + " %s @ %02x\n", client->name, + client->addr); + tcnt += ccnt; + } else { + ccnt = scnprintf(buf + tcnt, acnt - tcnt, + " no i2c client\n"); + tcnt += ccnt; } - ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n"); - tcnt += ccnt; } - mutex_unlock(&hdw->i2c_adap.clist_lock); return tcnt; } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 919a4f4e1..694e51f58 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -43,6 +43,18 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 }; module_param_array(ir_mode, int, NULL, 0444); MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR"); +static int pvr2_disable_ir_video; +module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video, + int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(disable_autoload_ir_video, + "1=do not try to autoload ir_video IR receiver"); + +/* Mapping of IR schemes to known I2C addresses - if any */ +static const unsigned char ir_video_addresses[] = { + [PVR2_IR_SCHEME_29XXX] = 0x18, + [PVR2_IR_SCHEME_24XXX] = 0x18, +}; + static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ u8 i2c_addr, /* I2C address we're talking to */ u8 *data, /* Data to write */ @@ -637,6 +649,31 @@ static void do_i2c_scan(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: i2c scan done.\n", hdw->name); } +static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) +{ + struct i2c_board_info info; + unsigned char addr = 0; + if (pvr2_disable_ir_video) { + pvr2_trace(PVR2_TRACE_INFO, + "Automatic binding of ir_video has been disabled."); + return; + } + if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) { + addr = ir_video_addresses[hdw->ir_scheme_active]; + } + if (!addr) { + /* The device either doesn't support I2C-based IR or we + don't know (yet) how to operate IR on the device. */ + return; + } + pvr2_trace(PVR2_TRACE_INFO, + "Binding ir_video to i2c address 0x%02x.", addr); + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + info.addr = addr; + i2c_new_device(&hdw->i2c_adap, &info); +} + void pvr2_i2c_core_init(struct pvr2_hdw *hdw) { unsigned int idx; @@ -652,7 +689,9 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: IR disabled\n",hdw->name); hdw->i2c_func[0x18] = i2c_black_hole; } else if (ir_mode[hdw->unit_number] == 1) { - if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_24XXX) { + if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) { + /* Set up translation so that our IR looks like a + 29xxx device */ hdw->i2c_func[0x18] = i2c_24xxx_ir; } } @@ -675,15 +714,23 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) i2c_add_adapter(&hdw->i2c_adap); if (hdw->i2c_func[0x18] == i2c_24xxx_ir) { /* Probe for a different type of IR receiver on this - device. If present, disable the emulated IR receiver. */ + device. This is really the only way to differentiate + older 24xxx devices from 24xxx variants that include an + IR blaster. If the IR blaster is present, the IR + receiver is part of that chip and thus we must disable + the emulated IR receiver. */ if (do_i2c_probe(hdw, 0x71)) { pvr2_trace(PVR2_TRACE_INFO, "Device has newer IR hardware;" " disabling unneeded virtual IR device"); hdw->i2c_func[0x18] = NULL; + /* Remember that this is a different device... */ + hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE; } } if (i2c_scan) do_i2c_scan(hdw); + + pvr2_i2c_register_ir(hdw); } void pvr2_i2c_core_done(struct pvr2_hdw *hdw) diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7ed3b8453..d8ad83df3 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -548,7 +548,7 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) &sfp->attr_unit_number); } pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); - sfp->class_dev->driver_data = NULL; + dev_set_drvdata(sfp->class_dev, NULL); device_unregister(sfp->class_dev); sfp->class_dev = NULL; } @@ -558,7 +558,7 @@ static ssize_t v4l_minor_number_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -570,7 +570,7 @@ static ssize_t bus_info_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_bus_info(sfp->channel.hdw)); @@ -581,7 +581,7 @@ static ssize_t hdw_name_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_type(sfp->channel.hdw)); @@ -592,7 +592,7 @@ static ssize_t hdw_desc_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n", pvr2_hdw_get_desc(sfp->channel.hdw)); @@ -604,7 +604,7 @@ static ssize_t v4l_radio_minor_number_show(struct device *class_dev, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, @@ -616,7 +616,7 @@ static ssize_t unit_number_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%d\n", pvr2_hdw_get_unit_number(sfp->channel.hdw)); @@ -644,7 +644,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp, class_dev->parent = &usb_dev->dev; sfp->class_dev = class_dev; - class_dev->driver_data = sfp; + dev_set_drvdata(class_dev, sfp); ret = device_register(class_dev); if (ret) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, @@ -817,7 +817,7 @@ static ssize_t debuginfo_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; pvr2_hdw_trigger_module_log(sfp->channel.hdw); return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); @@ -828,7 +828,7 @@ static ssize_t debugcmd_show(struct device *class_dev, struct device_attribute *attr, char *buf) { struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); } @@ -841,7 +841,7 @@ static ssize_t debugcmd_store(struct device *class_dev, struct pvr2_sysfs *sfp; int ret; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; + sfp = dev_get_drvdata(class_dev); if (!sfp) return -EINVAL; ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index c7fc605f8..a19ad36e5 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -91,7 +91,7 @@ static struct v4l2_capability pvr_capability ={ .driver = "pvrusb2", .card = "Hauppauge WinTV pvr-usb2", .bus_info = "usb", - .version = KERNEL_VERSION(0,8,0), + .version = KERNEL_VERSION(0, 9, 0), .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | V4L2_CAP_READWRITE), @@ -268,7 +268,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(&tmp,0,sizeof(tmp)); tmp.index = vi->index; ret = 0; - if ((vi->index < 0) || (vi->index >= fh->input_cnt)) { + if (vi->index >= fh->input_cnt) { ret = -EINVAL; break; } @@ -332,7 +332,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_S_INPUT: { struct v4l2_input *vi = (struct v4l2_input *)arg; - if ((vi->index < 0) || (vi->index >= fh->input_cnt)) { + if (vi->index >= fh->input_cnt) { ret = -ERANGE; break; } diff --git a/linux/drivers/media/video/pwc/pwc-v4l.c b/linux/drivers/media/video/pwc/pwc-v4l.c index bc0a46429..2876ce084 100644 --- a/linux/drivers/media/video/pwc/pwc-v4l.c +++ b/linux/drivers/media/video/pwc/pwc-v4l.c @@ -1107,7 +1107,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) return -EINVAL; if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; - if (buf->index < 0 || buf->index >= pwc_mbufs) + if (buf->index >= pwc_mbufs) return -EINVAL; buf->flags |= V4L2_BUF_FLAG_QUEUED; diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c index 12ced841e..203f6e3ff 100644 --- a/linux/drivers/media/video/s2255drv.c +++ b/linux/drivers/media/video/s2255drv.c @@ -110,6 +110,8 @@ #define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */ #define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */ #define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */ +/* SCALE_4CIFSI is the 2 fields interpolated into one */ +#define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */ #define COLOR_YUVPL 1 /* YUV planar */ #define COLOR_YUVPK 2 /* YUV packed */ @@ -239,6 +241,8 @@ struct s2255_dev { struct s2255_mode mode[MAX_CHANNELS]; /* jpeg compression */ struct v4l2_jpegcompression jc[MAX_CHANNELS]; + /* capture parameters (for high quality mode full size) */ + struct v4l2_captureparm cap_parm[MAX_CHANNELS]; const struct s2255_fmt *cur_fmt[MAX_CHANNELS]; int cur_frame[MAX_CHANNELS]; int last_frame[MAX_CHANNELS]; @@ -1021,9 +1025,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, fh->type = f->type; norm = norm_minw(fh->dev->vdev[fh->channel]); if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) { - if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) - fh->mode.scale = SCALE_4CIFS; - else + if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) { + if (fh->dev->cap_parm[fh->channel].capturemode & + V4L2_MODE_HIGHQUALITY) { + fh->mode.scale = SCALE_4CIFSI; + dprintk(2, "scale 4CIFSI\n"); + } else { + fh->mode.scale = SCALE_4CIFS; + dprintk(2, "scale 4CIFS\n"); + } + } else fh->mode.scale = SCALE_2CIFS; } else { @@ -1124,6 +1135,7 @@ static u32 get_transfer_size(struct s2255_mode *mode) if (mode->format == FORMAT_NTSC) { switch (mode->scale) { case SCALE_4CIFS: + case SCALE_4CIFSI: linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; pixelsPerLine = LINE_SZ_4CIFS_NTSC; break; @@ -1141,6 +1153,7 @@ static u32 get_transfer_size(struct s2255_mode *mode) } else if (mode->format == FORMAT_PAL) { switch (mode->scale) { case SCALE_4CIFS: + case SCALE_4CIFSI: linesPerFrame = NUM_LINES_4CIFS_PAL * 2; pixelsPerLine = LINE_SZ_4CIFS_PAL; break; @@ -1496,6 +1509,33 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, dprintk(2, "setting jpeg quality %d\n", jc->quality); return 0; } + +static int vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *sp) +{ + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode; + dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode); + return 0; +} + +static int vidioc_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *sp) +{ + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode; + dprintk(2, "setting param capture mode %d\n", + sp->parm.capture.capturemode); + return 0; +} static int s2255_open(struct file *file) { int minor = video_devdata(file)->minor; @@ -1787,6 +1827,8 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { #endif .vidioc_s_jpegcomp = vidioc_s_jpegcomp, .vidioc_g_jpegcomp = vidioc_g_jpegcomp, + .vidioc_s_parm = vidioc_s_parm, + .vidioc_g_parm = vidioc_g_parm, }; static struct video_device template = { @@ -2240,8 +2282,10 @@ static void read_pipe_completion(struct urb *purb) return; } status = purb->status; - if (status != 0) { - dprintk(2, "read_pipe_completion: err\n"); + /* if shutting down, do not resubmit, exit immediately */ + if (status == -ESHUTDOWN) { + dprintk(2, "read_pipe_completion: err shutdown\n"); + pipe_info->err_count++; return; } @@ -2250,9 +2294,13 @@ static void read_pipe_completion(struct urb *purb) return; } - s2255_read_video_callback(dev, pipe_info); + if (status == 0) + s2255_read_video_callback(dev, pipe_info); + else { + pipe_info->err_count++; + dprintk(1, "s2255drv: failed URB %d\n", status); + } - pipe_info->err_count = 0; pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); /* reuse urb */ usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, @@ -2264,7 +2312,6 @@ static void read_pipe_completion(struct urb *purb) if (pipe_info->state != 0) { if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) { dev_err(&dev->udev->dev, "error submitting urb\n"); - usb_free_urb(pipe_info->stream_urb); } } else { dprintk(2, "read pipe complete state 0\n"); diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig index 0ba68987b..5bcce092e 100644 --- a/linux/drivers/media/video/saa7134/Kconfig +++ b/linux/drivers/media/video/saa7134/Kconfig @@ -44,6 +44,7 @@ config VIDEO_SAA7134_DVB select DVB_LNBP21 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_TDA10048 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE ---help--- diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index 582a56c07..587209fdd 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -3403,13 +3403,15 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = { - .name = "Hauppauge WinTV-HVR1110r3", + .name = "Hauppauge WinTV-HVR1110r3 DVB-T/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, @@ -4826,7 +4828,6 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, .vmux = 3, @@ -6580,7 +6581,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_VIDEOMATE_DVBT_300: case SAA7134_BOARD_VIDEOMATE_DVBT_200: case SAA7134_BOARD_VIDEOMATE_DVBT_200A: - case SAA7134_BOARD_VIDEOMATE_T750: case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_BEHOLD_409FM: diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c index 69a214417..dc692d7a7 100644 --- a/linux/drivers/media/video/saa7134/saa7134-core.c +++ b/linux/drivers/media/video/saa7134/saa7134-core.c @@ -836,7 +836,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug; diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index 2e1344ecf..360fbdf19 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -48,6 +48,7 @@ #include "isl6405.h" #include "lnbp21.h" #include "tuner-simple.h" +#include "tda10048.h" #include "tda18271.h" #include "lgdt3305.h" #include "tda8290.h" @@ -978,6 +979,18 @@ static struct lgdt3305_config hcw_lgdt3305_config = { .vsb_if_khz = 3250, }; +static struct tda10048_config hcw_tda10048_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_SERIAL_OUTPUT, + .fwbulkwritelen = TDA10048_BULKWRITE_200, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3500, + .dtv8_if_freq_khz = TDA10048_IF_4000, + .clk_freq_khz = TDA10048_CLK_16000, + .disable_gate_access = 1, +}; + 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, }, @@ -1106,6 +1119,19 @@ static int dvb_init(struct saa7134_dev *dev) &tda827x_cfg_2) < 0) goto dettach_frontend; break; + case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + fe0->dvb.frontend = dvb_attach(tda10048_attach, + &hcw_tda10048_config, + &dev->i2c_adap); + if (fe0->dvb.frontend != NULL) { + 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_PHILIPS_TIGER: if (configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0) < 0) diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c index bab6b56c8..dd22a5215 100644 --- a/linux/drivers/media/video/saa7134/saa7134-empress.c +++ b/linux/drivers/media/video/saa7134/saa7134-empress.c @@ -499,11 +499,8 @@ static void empress_signal_update(struct work_struct *work) if (dev->nosignal) { dprintk("no video signal\n"); - ts_reset_encoder(dev); } else { dprintk("video signal acquired\n"); - if (atomic_read(&dev->empress_users)) - ts_init_encoder(dev); } } diff --git a/linux/drivers/media/video/saa7134/saa7134-i2c.c b/linux/drivers/media/video/saa7134/saa7134-i2c.c index 3eb60aabe..a8185693f 100644 --- a/linux/drivers/media/video/saa7134/saa7134-i2c.c +++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c @@ -264,7 +264,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, /* workaround for a saa7134 i2c bug * needed to talk to the mt352 demux * thanks to pinnacle for the hint */ - int quirk = 0xfd; + int quirk = 0xfe; d1printk(" [%02x quirk]",quirk); i2c_send_byte(dev,START,quirk); i2c_recv_byte(dev); @@ -326,33 +326,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -static int attach_inform(struct i2c_client *client) -{ - struct saa7134_dev *dev = client->adapter->algo_data; - - d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", - client->driver->driver.name, client->addr, client->name); - - /* Am I an i2c remote control? */ - - switch (client->addr) { - case 0x7a: - case 0x47: - case 0x71: - case 0x2d: - case 0x30: - { - struct IR_i2c *ir = i2c_get_clientdata(client); - d1printk("%s i2c IR detected (%s).\n", - client->driver->driver.name, ir->phys); - saa7134_set_i2c_ir(dev,ir); - break; - } - } - - return 0; -} - static struct i2c_algorithm saa7134_algo = { .master_xfer = saa7134_i2c_xfer, .functionality = functionality, @@ -369,7 +342,6 @@ static struct i2c_adapter saa7134_adap_template = { .name = "saa7134", .id = I2C_HW_SAA7134, .algo = &saa7134_algo, - .client_register = attach_inform, }; static struct i2c_client saa7134_client_template = { @@ -444,6 +416,9 @@ int saa7134_i2c_register(struct saa7134_dev *dev) saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); if (i2c_scan) do_i2c_scan(dev->name,&dev->i2c_client); + + /* Instantiate the IR receiver device, if present */ + saa7134_probe_i2c_ir(dev); return 0; } diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c index 80a4cc23d..36913d22b 100644 --- a/linux/drivers/media/video/saa7134/saa7134-input.c +++ b/linux/drivers/media/video/saa7134/saa7134-input.c @@ -60,7 +60,7 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of " #define dprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) #define i2cdprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg) /* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */ static int saa7134_rc5_irq(struct saa7134_dev *dev); @@ -134,10 +134,10 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, int gpio; /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ - struct saa7134_dev *dev = ir->c.adapter->algo_data; + struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { dprintk("get_key_msi_tvanywhere_plus: " - "gir->c.adapter->algo_data is NULL!\n"); + "gir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -156,7 +156,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, /* GPIO says there is a button press. Get it. */ - if (1 != i2c_master_recv(&ir->c, &b, 1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { i2cdprintk("read error\n"); return -EIO; } @@ -179,7 +179,7 @@ static int get_key_purpletv(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)) { i2cdprintk("read error\n"); return -EIO; } @@ -202,7 +202,7 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char buf[5], cod4, code3, code4; /* poll IR chip */ - if (5 != i2c_master_recv(&ir->c,buf,5)) + if (5 != i2c_master_recv(ir->c, buf, 5)) return -EIO; cod4 = buf[4]; @@ -224,7 +224,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char data[12]; u32 gpio; - struct saa7134_dev *dev = ir->c.adapter->algo_data; + struct saa7134_dev *dev = ir->c->adapter->algo_data; /* rising SAA7134_GPIO_GPRESCAN reads the status */ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); @@ -235,9 +235,9 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) if (0x400000 & ~gpio) return 0; /* No button press */ - ir->c.addr = 0x5a >> 1; + ir->c->addr = 0x5a >> 1; - if (12 != i2c_master_recv(&ir->c, data, 12)) { + if (12 != i2c_master_recv(ir->c, data, 12)) { i2cdprintk("read error\n"); return -EIO; } @@ -267,7 +267,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, unsigned int start = 0,parity = 0,code = 0; /* poll IR chip */ - if (4 != i2c_master_recv(&ir->c, b, 4)) { + if (4 != i2c_master_recv(ir->c, b, 4)) { i2cdprintk("read error\n"); return -EIO; } @@ -686,40 +686,68 @@ void saa7134_input_fini(struct saa7134_dev *dev) dev->remote = NULL; } -void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) +void saa7134_probe_i2c_ir(struct saa7134_dev *dev) { + struct i2c_board_info info; + struct IR_i2c_init_data init_data; + const unsigned short addr_list[] = { + 0x7a, 0x47, 0x71, 0x2d, + I2C_CLIENT_END + }; + + struct i2c_msg msg_msi = { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 0, + .buf = NULL, + }; + + int rc; + if (disable_ir) { - dprintk("Found supported i2c remote, but IR has been disabled\n"); - ir->get_key=NULL; + dprintk("IR has been disabled, not probing for i2c remote\n"); return; } + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + switch (dev->board) { case SAA7134_BOARD_PINNACLE_PCTV_110i: case SAA7134_BOARD_PINNACLE_PCTV_310i: - snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV"); + init_data.name = "Pinnacle PCTV"; if (pinnacle_remote == 0) { - ir->get_key = get_key_pinnacle_color; - ir->ir_codes = ir_codes_pinnacle_color; + init_data.get_key = get_key_pinnacle_color; + init_data.ir_codes = ir_codes_pinnacle_color; } else { - ir->get_key = get_key_pinnacle_grey; - ir->ir_codes = ir_codes_pinnacle_grey; + init_data.get_key = get_key_pinnacle_grey; + init_data.ir_codes = ir_codes_pinnacle_grey; } break; case SAA7134_BOARD_UPMOST_PURPLE_TV: - snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV"); - ir->get_key = get_key_purpletv; - ir->ir_codes = ir_codes_purpletv; + init_data.name = "Purple TV"; + init_data.get_key = get_key_purpletv; + init_data.ir_codes = ir_codes_purpletv; break; case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: - snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus"); - ir->get_key = get_key_msi_tvanywhere_plus; - ir->ir_codes = ir_codes_msi_tvanywhere_plus; + init_data.name = "MSI TV@nywhere Plus"; + init_data.get_key = get_key_msi_tvanywhere_plus; + init_data.ir_codes = ir_codes_msi_tvanywhere_plus; + info.addr = 0x30; + /* MSI TV@nywhere Plus controller doesn't seem to + respond to probes unless we read something from + an existing device. Weird... + REVISIT: might no longer be needed */ + rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); + dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n", + msg_msi.addr, dev->i2c_adap.name, + (1 == rc) ? "yes" : "no"); break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: - snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110"); - ir->get_key = get_key_hvr1110; - ir->ir_codes = ir_codes_hauppauge_new; + init_data.name = "HVR 1110"; + init_data.get_key = get_key_hvr1110; + init_data.ir_codes = ir_codes_hauppauge_new; break; case SAA7134_BOARD_BEHOLD_607FM_MK3: case SAA7134_BOARD_BEHOLD_607FM_MK5: @@ -733,15 +761,26 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) case SAA7134_BOARD_BEHOLD_M63: case SAA7134_BOARD_BEHOLD_M6_EXTRA: 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; + init_data.name = "BeholdTV"; + init_data.get_key = get_key_beholdm6xx; + init_data.ir_codes = ir_codes_behold; break; - default: - dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board); + case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: + case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: + info.addr = 0x40; break; } + if (init_data.name) + info.platform_data = &init_data; + /* No need to probe if address is known */ + if (info.addr) { + i2c_new_device(&dev->i2c_adap, &info); + return; + } + + /* Address not known, fallback to probing */ + i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); } static int saa7134_rc5_irq(struct saa7134_dev *dev) diff --git a/linux/drivers/media/video/saa7134/saa7134-ts.c b/linux/drivers/media/video/saa7134/saa7134-ts.c index cc8b923af..b8ff459d0 100644 --- a/linux/drivers/media/video/saa7134/saa7134-ts.c +++ b/linux/drivers/media/video/saa7134/saa7134-ts.c @@ -65,7 +65,7 @@ static int buffer_activate(struct saa7134_dev *dev, /* start DMA */ saa7134_set_dmabits(dev); - mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT); if (dev->ts_state == SAA7134_TS_BUFF_DONE) { /* Clear TS cache */ diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c index 5f68bed54..26f1727e6 100644 --- a/linux/drivers/media/video/saa7134/saa7134-video.c +++ b/linux/drivers/media/video/saa7134/saa7134-video.c @@ -1423,11 +1423,13 @@ video_poll(struct file *file, struct poll_table_struct *wait) { struct saa7134_fh *fh = file->private_data; struct videobuf_buffer *buf = NULL; + unsigned int rc = 0; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) return videobuf_poll_stream(file, &fh->vbi, wait); if (res_check(fh,RESOURCE_VIDEO)) { + mutex_lock(&fh->cap.vb_lock); if (!list_empty(&fh->cap.stream)) buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); } else { @@ -1446,13 +1448,14 @@ video_poll(struct file *file, struct poll_table_struct *wait) } if (!buf) - return POLLERR; + rc = POLLERR; poll_wait(file, &buf->done, wait); if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - return 0; + rc = POLLIN|POLLRDNORM; + mutex_unlock(&fh->cap.vb_lock); + return rc; err: mutex_unlock(&fh->cap.vb_lock); diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index d961e0861..be6763dde 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -377,6 +377,7 @@ struct saa7134_board { #define INTERLACE_OFF 2 #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ +#define TS_BUFFER_TIMEOUT msecs_to_jiffies(1000) /* 1 second */ struct saa7134_dev; struct saa7134_dma; @@ -803,7 +804,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status); int saa7134_input_init1(struct saa7134_dev *dev); void saa7134_input_fini(struct saa7134_dev *dev); void saa7134_input_irq(struct saa7134_dev *dev); -void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir); +void saa7134_probe_i2c_ir(struct saa7134_dev *dev); void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir); void saa7134_ir_stop(struct saa7134_dev *dev); diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index f792ab2e5..822052b25 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -1204,7 +1204,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) return 0; } -static struct platform_driver soc_camera_pdrv = { +static struct platform_driver __refdata soc_camera_pdrv = { .probe = soc_camera_pdrv_probe, .remove = __exit_p(soc_camera_pdrv_remove), .driver = { diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c index 7cbc4f736..886caf736 100644 --- a/linux/drivers/media/video/stk-webcam.c +++ b/linux/drivers/media/video/stk-webcam.c @@ -1138,7 +1138,7 @@ static int stk_vidioc_querybuf(struct file *filp, struct stk_camera *dev = priv; struct stk_sio_buffer *sbuf; - if (buf->index < 0 || buf->index >= dev->n_sbufs) + if (buf->index >= dev->n_sbufs) return -EINVAL; sbuf = dev->sio_bufs + buf->index; *buf = sbuf->v4lbuf; @@ -1155,7 +1155,7 @@ static int stk_vidioc_qbuf(struct file *filp, if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; - if (buf->index < 0 || buf->index >= dev->n_sbufs) + if (buf->index >= dev->n_sbufs) return -EINVAL; sbuf = dev->sio_bufs + buf->index; if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c index de866798b..910e156f4 100644 --- a/linux/drivers/media/video/tea6415c.c +++ b/linux/drivers/media/video/tea6415c.c @@ -147,7 +147,6 @@ static const struct v4l2_subdev_ops tea6415c_ops = { .video = &tea6415c_video_ops, }; -/* this function is called by i2c_probe */ static int tea6415c_probe(struct i2c_client *client, const struct i2c_device_id *id) { diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c index 90054dfbe..0e7bb8d6a 100644 --- a/linux/drivers/media/video/tea6420.c +++ b/linux/drivers/media/video/tea6420.c @@ -118,7 +118,6 @@ static const struct v4l2_subdev_ops tea6420_ops = { .audio = &tea6420_audio_ops, }; -/* this function is called by i2c_probe */ static int tea6420_probe(struct i2c_client *client, const struct i2c_device_id *id) { diff --git a/linux/drivers/media/video/ths7303.c b/linux/drivers/media/video/ths7303.c new file mode 100644 index 000000000..21781f8a0 --- /dev/null +++ b/linux/drivers/media/video/ths7303.c @@ -0,0 +1,151 @@ +/* + * ths7303- THS7303 Video Amplifier driver + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/ctype.h> +#include <linux/i2c.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/uaccess.h> +#include <linux/videodev2.h> + +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-chip-ident.h> + +MODULE_DESCRIPTION("TI THS7303 video amplifier driver"); +MODULE_AUTHOR("Chaithrika U S"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +/* following function is used to set ths7303 */ +static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std) +{ + int err = 0; + u8 val; + struct i2c_client *client; + + client = v4l2_get_subdevdata(sd); + + if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) { + val = 0x02; + v4l2_dbg(1, debug, sd, "setting value for SDTV format\n"); + } else { + val = 0x00; + v4l2_dbg(1, debug, sd, "disabling all channels\n"); + } + + err |= i2c_smbus_write_byte_data(client, 0x01, val); + err |= i2c_smbus_write_byte_data(client, 0x02, val); + err |= i2c_smbus_write_byte_data(client, 0x03, val); + + if (err) + v4l2_err(sd, "write failed\n"); + + return err; +} + +static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + return ths7303_setvalue(sd, norm); +} + +static int ths7303_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0); +} + +static const struct v4l2_subdev_video_ops ths7303_video_ops = { + .s_std_output = ths7303_s_std_output, +}; + +static const struct v4l2_subdev_core_ops ths7303_core_ops = { + .g_chip_ident = ths7303_g_chip_ident, +}; + +static const struct v4l2_subdev_ops ths7303_ops = { + .core = &ths7303_core_ops, + .video = &ths7303_video_ops, +}; + +static int ths7303_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct v4l2_subdev *sd; + v4l2_std_id std_id = V4L2_STD_NTSC; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + if (sd == NULL) + return -ENOMEM; + + v4l2_i2c_subdev_init(sd, client, &ths7303_ops); + + return ths7303_setvalue(sd, std_id); +} + +static int ths7303_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(sd); + + return 0; +} + +static const struct i2c_device_id ths7303_id[] = { + {"ths7303", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ths7303_id); + +static struct i2c_driver ths7303_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ths7303", + }, + .probe = ths7303_probe, + .remove = ths7303_remove, + .id_table = ths7303_id, +}; + +static int __init ths7303_init(void) +{ + return i2c_add_driver(&ths7303_driver); +} + +static void __exit ths7303_exit(void) +{ + i2c_del_driver(&ths7303_driver); +} + +module_init(ths7303_init); +module_exit(ths7303_exit); + diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c index bb60c910e..cb715f143 100644 --- a/linux/drivers/media/video/tuner-core.c +++ b/linux/drivers/media/video/tuner-core.c @@ -434,10 +434,6 @@ static void set_type(struct i2c_client *c, unsigned int type, if (!dvb_attach(xc5000_attach, &t->fe, t->i2c->adapter, &xc5000_cfg)) goto attach_failed; - - xc_tuner_ops = &t->fe.ops.tuner_ops; - if (xc_tuner_ops->init) - xc_tuner_ops->init(&t->fe); break; } default: diff --git a/linux/drivers/media/video/tveeprom.c b/linux/drivers/media/video/tveeprom.c index cdea91aae..7d6459dd2 100644 --- a/linux/drivers/media/video/tveeprom.c +++ b/linux/drivers/media/video/tveeprom.c @@ -211,7 +211,7 @@ hauppauge_tuner[] = { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, { TUNER_ABSENT, "Panasonic ENV57H12D5"}, { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, - { TUNER_ABSENT, "TCL MNM05-4"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MNM05-4"}, { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, { TUNER_ABSENT, "TCL MQNM05-4"}, { TUNER_ABSENT, "LG TAPC-W701D"}, diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c index d7056a5b7..d03e5922d 100644 --- a/linux/drivers/media/video/usbvision/usbvision-video.c +++ b/linux/drivers/media/video/usbvision/usbvision-video.c @@ -541,7 +541,7 @@ static int vidioc_enum_input (struct file *file, void *priv, struct usb_usbvision *usbvision = video_drvdata(file); int chan; - if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) ) + if (vi->index >= usbvision->video_inputs) return -EINVAL; if (usbvision->have_tuner) { chan = vi->index; diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 4a69a3af6..8d193376c 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -289,10 +289,8 @@ static int uvc_parse_format(struct uvc_device *dev, struct uvc_format_desc *fmtdesc; struct uvc_frame *frame; const unsigned char *start = buffer; - unsigned char *_buffer; unsigned int interval; unsigned int i, n; - int _buflen; __u8 ftype; format->type = buffer[2]; @@ -303,7 +301,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_FRAME_BASED: n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28; if (buflen < n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -338,7 +336,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_MJPEG: if (buflen < 11) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -354,7 +352,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_DV: if (buflen < 9) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -372,7 +370,7 @@ static int uvc_parse_format(struct uvc_device *dev, strlcpy(format->name, "HD-DV", sizeof format->name); break; default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d: unknown DV format %u\n", dev->udev->devnum, alts->desc.bInterfaceNumber, buffer[8]); @@ -401,7 +399,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_STREAM_BASED: /* Not supported yet. */ default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d unsupported format %u\n", dev->udev->devnum, alts->desc.bInterfaceNumber, buffer[2]); @@ -413,20 +411,11 @@ static int uvc_parse_format(struct uvc_device *dev, buflen -= buffer[0]; buffer += buffer[0]; - /* Count the number of frame descriptors to test the bFrameIndex - * field when parsing the descriptors. We can't rely on the - * bNumFrameDescriptors field as some cameras don't initialize it - * properly. - */ - for (_buflen = buflen, _buffer = buffer; - _buflen > 2 && _buffer[2] == ftype; - _buflen -= _buffer[0], _buffer += _buffer[0]) - format->nframes++; - /* Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ while (buflen > 2 && buffer[2] == ftype) { + frame = &format->frame[format->nframes]; if (ftype != VS_FRAME_FRAME_BASED) n = buflen > 25 ? buffer[25] : 0; else @@ -435,22 +424,12 @@ static int uvc_parse_format(struct uvc_device *dev, n = n ? n : 3; if (buflen < 26 + 4*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FRAME error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } - if (buffer[3] - 1 >= format->nframes) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" - "interface %d frame index %u out of range\n", - dev->udev->devnum, alts->desc.bInterfaceNumber, - buffer[3]); - return -EINVAL; - } - - frame = &format->frame[buffer[3] - 1]; - frame->bFrameIndex = buffer[3]; frame->bmCapabilities = buffer[4]; frame->wWidth = get_unaligned_le16(&buffer[5]); @@ -507,6 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev, 10000000/frame->dwDefaultFrameInterval, (100000000/frame->dwDefaultFrameInterval)%10); + format->nframes++; buflen -= buffer[0]; buffer += buffer[0]; } @@ -518,7 +498,7 @@ static int uvc_parse_format(struct uvc_device *dev, if (buflen > 2 && buffer[2] == VS_COLORFORMAT) { if (buflen < 6) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d COLORFORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -1316,7 +1296,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video, continue; if (forward->extension.bNrInPins != 1) { - uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has" + uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has " "more than 1 input pin.\n", entity->id); return -1; } @@ -1614,6 +1594,7 @@ static int uvc_probe(struct usb_interface *intf, INIT_LIST_HEAD(&dev->entities); INIT_LIST_HEAD(&dev->streaming); kref_init(&dev->kref); + atomic_set(&dev->users, 0); dev->udev = usb_get_dev(udev); dev->intf = usb_get_intf(intf); @@ -1929,7 +1910,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Lenovo Thinkpad SL500 */ + /* Lenovo Thinkpad SL400/SL500 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x17ef, diff --git a/linux/drivers/media/video/uvc/uvc_status.c b/linux/drivers/media/video/uvc/uvc_status.c index 1e1bda413..b05df63b4 100644 --- a/linux/drivers/media/video/uvc/uvc_status.c +++ b/linux/drivers/media/video/uvc/uvc_status.c @@ -206,7 +206,7 @@ int uvc_status_init(struct uvc_device *dev) dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, dev, interval); - return usb_submit_urb(dev->int_urb, GFP_KERNEL); + return 0; } void uvc_status_cleanup(struct uvc_device *dev) @@ -217,15 +217,30 @@ void uvc_status_cleanup(struct uvc_device *dev) uvc_input_cleanup(dev); } -int uvc_status_suspend(struct uvc_device *dev) +int uvc_status_start(struct uvc_device *dev) +{ + if (dev->int_urb == NULL) + return 0; + + return usb_submit_urb(dev->int_urb, GFP_KERNEL); +} + +void uvc_status_stop(struct uvc_device *dev) { usb_kill_urb(dev->int_urb); +} + +int uvc_status_suspend(struct uvc_device *dev) +{ + if (atomic_read(&dev->users)) + usb_kill_urb(dev->int_urb); + return 0; } int uvc_status_resume(struct uvc_device *dev) { - if (dev->int_urb == NULL) + if (dev->int_urb == NULL || atomic_read(&dev->users) == 0) return 0; return usb_submit_urb(dev->int_urb, GFP_NOIO); diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index bc13dbf05..160c01314 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -443,6 +443,17 @@ static int uvc_v4l2_open(struct file *file) goto done; } + if (atomic_inc_return(&video->dev->users) == 1) { + if ((ret = uvc_status_start(video->dev)) < 0) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) + usb_autopm_put_interface(video->dev->intf); +#endif + atomic_dec(&video->dev->users); + kfree(handle); + goto done; + } + } + handle->device = video; handle->state = UVC_HANDLE_PASSIVE; file->private_data = handle; @@ -477,6 +488,9 @@ static int uvc_v4l2_release(struct file *file) kfree(handle); file->private_data = NULL; + if (atomic_dec_return(&video->dev->users) == 0) + uvc_status_stop(video->dev); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) usb_autopm_put_interface(video->dev->intf); #endif diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index c5df33de9..07e755ba7 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -65,7 +65,8 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, struct uvc_streaming_control *ctrl) { struct uvc_format *format; - struct uvc_frame *frame; + struct uvc_frame *frame = NULL; + unsigned int i; if (ctrl->bFormatIndex <= 0 || ctrl->bFormatIndex > video->streaming->nformats) @@ -73,11 +74,15 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, format = &video->streaming->format[ctrl->bFormatIndex - 1]; - if (ctrl->bFrameIndex <= 0 || - ctrl->bFrameIndex > format->nframes) - return; + for (i = 0; i < format->nframes; ++i) { + if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) { + frame = &format->frame[i]; + break; + } + } - frame = &format->frame[ctrl->bFrameIndex - 1]; + if (frame == NULL) + return; if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) || (ctrl->dwMaxVideoFrameSize == 0 && @@ -1093,7 +1098,7 @@ int uvc_video_init(struct uvc_video_device *video) /* Zero bFrameIndex might be correct. Stream-based formats (including * MPEG-2 TS and DV) do not support frames but have a dummy frame * descriptor with bFrameIndex set to zero. If the default frame - * descriptor is not found, use the first avalable frame. + * descriptor is not found, use the first available frame. */ for (i = format->nframes; i > 0; --i) { frame = &format->frame[i-1]; diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h index 53d5c9e0c..6b254fd39 100644 --- a/linux/drivers/media/video/uvc/uvcvideo.h +++ b/linux/drivers/media/video/uvc/uvcvideo.h @@ -635,6 +635,7 @@ struct uvc_device { enum uvc_device_state state; struct kref kref; struct list_head list; + atomic_t users; /* Video control interface */ __u16 uvc_version; @@ -771,6 +772,8 @@ extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, /* Status */ extern int uvc_status_init(struct uvc_device *dev); extern void uvc_status_cleanup(struct uvc_device *dev); +extern int uvc_status_start(struct uvc_device *dev); +extern void uvc_status_stop(struct uvc_device *dev); extern int uvc_status_suspend(struct uvc_device *dev); extern int uvc_status_resume(struct uvc_device *dev); diff --git a/linux/drivers/media/video/v4l2-device.c b/linux/drivers/media/video/v4l2-device.c index c76f83840..b962862fe 100644 --- a/linux/drivers/media/video/v4l2-device.c +++ b/linux/drivers/media/video/v4l2-device.c @@ -86,6 +86,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) /* Unregister subdevs */ list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) { v4l2_device_unregister_subdev(sd); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -96,6 +97,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) if (client) i2c_unregister_device(client); } +#endif } } EXPORT_SYMBOL_GPL(v4l2_device_unregister); diff --git a/linux/drivers/media/video/videobuf-core.c b/linux/drivers/media/video/videobuf-core.c index b104cd593..e9696385d 100644 --- a/linux/drivers/media/video/videobuf-core.c +++ b/linux/drivers/media/video/videobuf-core.c @@ -440,6 +440,7 @@ int videobuf_reqbufs(struct videobuf_queue *q, } req->count = retval; + retval = 0; done: mutex_unlock(&q->vb_lock); @@ -455,7 +456,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) dprintk(1, "querybuf: Wrong type.\n"); goto done; } - if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { + if (unlikely(b->index >= VIDEO_MAX_FRAME)) { dprintk(1, "querybuf: index out of range.\n"); goto done; } @@ -496,7 +497,7 @@ int videobuf_qbuf(struct videobuf_queue *q, dprintk(1, "qbuf: Wrong type.\n"); goto done; } - if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { + if (b->index >= VIDEO_MAX_FRAME) { dprintk(1, "qbuf: index out of range.\n"); goto done; } diff --git a/linux/drivers/media/video/videobuf-dma-contig.c b/linux/drivers/media/video/videobuf-dma-contig.c index 6db1398fd..633a124cf 100644 --- a/linux/drivers/media/video/videobuf-dma-contig.c +++ b/linux/drivers/media/video/videobuf-dma-contig.c @@ -183,19 +183,6 @@ static int __videobuf_iolock(struct videobuf_queue *q, return 0; } -static int __videobuf_sync(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size, - DMA_FROM_DEVICE); - return 0; -} - static int __videobuf_mmap_free(struct videobuf_queue *q) { unsigned int i; @@ -357,7 +344,6 @@ static struct videobuf_qtype_ops qops = { .alloc = __videobuf_alloc, .iolock = __videobuf_iolock, - .sync = __videobuf_sync, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, .video_copy_to_user = __videobuf_copy_to_user, diff --git a/linux/drivers/media/video/videobuf-dma-sg.c b/linux/drivers/media/video/videobuf-dma-sg.c index ed38145e1..623e2fc12 100644 --- a/linux/drivers/media/video/videobuf-dma-sg.c +++ b/linux/drivers/media/video/videobuf-dma-sg.c @@ -59,9 +59,10 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) struct page *pg; int i; - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + sglist = vmalloc(nr_pages * sizeof(*sglist)); if (NULL == sglist) return NULL; + memset(sglist, 0, nr_pages * sizeof(*sglist)); sg_init_table(sglist, nr_pages); for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { pg = vmalloc_to_page(virt); @@ -73,7 +74,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) return sglist; err: - kfree(sglist); + vfree(sglist); return NULL; } @@ -85,7 +86,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) if (NULL == pages[0]) return NULL; - sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL); + sglist = vmalloc(nr_pages * sizeof(*sglist)); if (NULL == sglist) return NULL; sg_init_table(sglist, nr_pages); @@ -105,12 +106,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) nopage: dprintk(2,"sgl: oops - no page\n"); - kfree(sglist); + vfree(sglist); return NULL; highmem: dprintk(2,"sgl: oops - highmem page\n"); - kfree(sglist); + vfree(sglist); return NULL; } @@ -231,7 +232,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma) (dma->vmalloc,dma->nr_pages); } if (dma->bus_addr) { - dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + dma->sglist = vmalloc(sizeof(*dma->sglist)); if (NULL != dma->sglist) { dma->sglen = 1; sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; @@ -249,7 +250,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma) if (0 == dma->sglen) { printk(KERN_WARNING "%s: videobuf_map_sg failed\n",__func__); - kfree(dma->sglist); + vfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; return -EIO; @@ -275,7 +276,7 @@ int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction); - kfree(dma->sglist); + vfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; return 0; diff --git a/linux/drivers/media/video/zoran/zoran_card.c b/linux/drivers/media/video/zoran/zoran_card.c index 733db7690..67ab10878 100644 --- a/linux/drivers/media/video/zoran/zoran_card.c +++ b/linux/drivers/media/video/zoran/zoran_card.c @@ -1023,7 +1023,7 @@ zr36057_init (struct zoran *zr) zr->vbuf_bytesperline = 0; /* Avoid nonsense settings from user for default input/norm */ - if (default_norm < 0 && default_norm > 2) + if (default_norm < 0 || default_norm > 2) default_norm = 0; if (default_norm == 0) { zr->norm = V4L2_STD_PAL; diff --git a/linux/include/media/adv7343.h b/linux/include/media/adv7343.h new file mode 100644 index 000000000..d6f8a4e1a --- /dev/null +++ b/linux/include/media/adv7343.h @@ -0,0 +1,23 @@ +/* + * ADV7343 header file + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.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 version 2. + * + * This program is distributed .as is. WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef ADV7343_H +#define ADV7343_H + +#define ADV7343_COMPOSITE_ID (0) +#define ADV7343_COMPONENT_ID (1) +#define ADV7343_SVIDEO_ID (2) + +#endif /* End of #ifndef ADV7343_H */ diff --git a/linux/include/media/ir-kbd-i2c.h b/linux/include/media/ir-kbd-i2c.h index 07963d705..3ad4ed540 100644 --- a/linux/include/media/ir-kbd-i2c.h +++ b/linux/include/media/ir-kbd-i2c.h @@ -7,7 +7,7 @@ struct IR_i2c; struct IR_i2c { IR_KEYTAB_TYPE *ir_codes; - struct i2c_client c; + struct i2c_client *c; struct input_dev *input; struct ir_input_state ir; @@ -15,7 +15,15 @@ struct IR_i2c { unsigned char old; struct delayed_work work; + char name[32]; char phys[32]; int (*get_key)(struct IR_i2c*, u32*, u32*); }; + +/* Can be passed when instantiating an ir_video i2c device */ +struct IR_i2c_init_data { + IR_KEYTAB_TYPE *ir_codes; + const char *name; + int (*get_key)(struct IR_i2c*, u32*, u32*); +}; #endif diff --git a/linux/include/media/tuner.h b/linux/include/media/tuner.h index 7d4e2db78..735a2a941 100644 --- a/linux/include/media/tuner.h +++ b/linux/include/media/tuner.h @@ -124,6 +124,7 @@ #define TUNER_XC5000 76 /* Xceive Silicon Tuner */ #define TUNER_TCL_MF02GIP_5N 77 /* TCL MF02GIP_5N */ #define TUNER_PHILIPS_FMD1216MEX_MK3 78 +#define TUNER_PHILIPS_FM1216MK5 79 /* tv card specific */ #define TDA9887_PRESENT (1<<0) diff --git a/linux/include/media/v4l2-chip-ident.h b/linux/include/media/v4l2-chip-ident.h index 1be461a29..4d7e2272c 100644 --- a/linux/include/media/v4l2-chip-ident.h +++ b/linux/include/media/v4l2-chip-ident.h @@ -137,6 +137,12 @@ enum { /* module saa7191: just ident 7191 */ V4L2_IDENT_SAA7191 = 7191, + /* module ths7303: just ident 7303 */ + V4L2_IDENT_THS7303 = 7303, + + /* module adv7343: just ident 7343 */ + V4L2_IDENT_ADV7343 = 7343, + /* module wm8739: just ident 8739 */ V4L2_IDENT_WM8739 = 8739, diff --git a/v4l/scripts/gentree.pl b/v4l/scripts/gentree.pl index 1968bb334..b9053f464 100755..100644 --- a/v4l/scripts/gentree.pl +++ b/v4l/scripts/gentree.pl @@ -22,8 +22,8 @@ # If gentree knows the result of an expression, that directive will be # "processed", otherwise it will be an "other". gentree knows the value # of LINUX_VERSION_CODE, BTTV_VERSION_CODE, the KERNEL_VERSION(x,y,z) -# macro, numeric constants like 0 and 1, and a few defines like MM_KERNEL -# and STV0297_CS2. +# macro, numeric constants like 0 and 1, and a few defines like +# I2C_CLASS_TV_DIGITAL # # An exception is if the comment "/*KEEP*/" appears after the expression, # in which case that directive will be considered an "other" and not @@ -55,22 +55,10 @@ my %defs = ( 'LINUX_VERSION_CODE' => $LINUXCODE, 'BTTV_VERSION_CODE' => $BTTVCODE, '_COMPAT_H' => 0, - 'MM_KERNEL' => ($extra =~ /-mm/)?1:0, - 'BROKEN_XAWTV' => 0, - 'STV0297_CS2' => 0, - 'HAVE_VIDEO_BUF_DVB' => 1, - 'I2C_PEC' => 1, - 'I2C_DF_DUMMY' => 0, - 'CONFIG_XC3028' => 0, - 'HAVE_XC2028'=> 0, - 'HAVE_XC3028' => 0, 'I2C_CLASS_TV_ANALOG' => 1, 'I2C_CLASS_TV_DIGITAL' => 1, 'OLD_XMIT_LOCK' => 0, 'COMPAT_SND_CTL_BOOLEAN_MONO' => 0, - 'CONFIG_VIVI_SCATTER' => 0, - 'CONFIG_BIGPHYS_AREA' => 0, - 'BUZ_USE_HIMEM' => 1, 'NEED_SOUND_DRIVER_H' => 0, 'TTUSB_KERNEL' => 1, 'NO_PCM_LOCK' => 0, |