diff options
Diffstat (limited to 'drivers/media')
235 files changed, 14200 insertions, 13255 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 9575db429df4..d941581ab921 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -6,20 +6,82 @@ menuconfig MEDIA_SUPPORT tristate "Multimedia support" depends on HAS_IOMEM help - If you want to use Video for Linux, DVB for Linux, or DAB adapters, + If you want to use Webcams, Video grabber devices and/or TV devices enable this option and other options below. + Additional info and docs are available on the web at + <http://linuxtv.org> if MEDIA_SUPPORT comment "Multimedia core support" # +# Multimedia support - automatically enable V4L2 and DVB core +# +config MEDIA_CAMERA_SUPPORT + bool "Cameras/video grabbers support" + ---help--- + Enable support for webcams and video grabbers. + + Say Y when you have a webcam or a video capture grabber board. + +config MEDIA_ANALOG_TV_SUPPORT + bool "Analog TV support" + ---help--- + Enable analog TV support. + + Say Y when you have a TV board with analog support or with a + hybrid analog/digital TV chipset. + + Note: There are several DVB cards that are based on chips that + support both analog and digital TV. Disabling this option + will disable support for them. + +config MEDIA_DIGITAL_TV_SUPPORT + bool "Digital TV support" + ---help--- + Enable digital TV support. + + Say Y when you have a board with digital support or a board with + hybrid digital TV and analog TV. + +config MEDIA_RADIO_SUPPORT + bool "AM/FM radio receivers/transmitters support" + ---help--- + Enable AM/FM radio support. + + Additional info and docs are available on the web at + <http://linuxtv.org> + + Say Y when you have a board with radio support. + + Note: There are several TV cards that are based on chips that + support radio reception. Disabling this option will + disable support for them. + +config MEDIA_RC_SUPPORT + bool "Remote Controller support" + depends on INPUT + ---help--- + Enable support for Remote Controllers on Linux. This is + needed in order to support several video capture adapters, + standalone IR receivers/transmitters, and RF receivers. + + Enable this option if you have a video capture board even + if you don't need IR, as otherwise, you may not be able to + compile the driver for your adapter. + + Say Y when you have a TV or an IR device. + +# # Media controller +# Selectable only for webcam/grabbers, as other drivers don't use it # config MEDIA_CONTROLLER bool "Media Controller API (EXPERIMENTAL)" depends on EXPERIMENTAL + depends on MEDIA_CAMERA_SUPPORT ---help--- Enable the media controller API used to query media devices internal topology and configure it dynamically. @@ -27,26 +89,15 @@ config MEDIA_CONTROLLER This API is mostly used by camera interfaces in embedded platforms. # -# V4L core and enabled API's +# Video4Linux support +# Only enables if one of the V4L2 types (ATV, webcam, radio) is selected # config VIDEO_DEV - tristate "Video For Linux" - ---help--- - V4L core support for video capture and overlay devices, webcams and - AM/FM radio cards. - - This kernel includes support for the new Video for Linux Two API, - (V4L2). - - Additional info and docs are available on the web at - <http://linuxtv.org> - - Documentation for V4L2 is also available on the web at - <http://bytesex.org/v4l/>. - - To compile this driver as a module, choose M here: the - module will be called videodev. + tristate + depends on MEDIA_SUPPORT + depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT + default y config VIDEO_V4L2_COMMON tristate @@ -64,25 +115,15 @@ config VIDEO_V4L2_SUBDEV_API # # DVB Core +# Only enables if one of DTV is selected # config DVB_CORE - tristate "DVB for Linux" + tristate + depends on MEDIA_SUPPORT + depends on MEDIA_DIGITAL_TV_SUPPORT + default y select CRC32 - help - DVB core utility functions for device handling, software fallbacks etc. - - Enable this if you own a DVB/ATSC adapter and want to use it or if - you compile Linux for a digital SetTopBox. - - Say Y when you have a DVB or an ATSC card and want to use it. - - API specs and user tools are available from <http://www.linuxtv.org/>. - - Please report problems regarding this support to the LinuxDVB - mailing list. - - If unsure say N. config DVB_NET bool "DVB Network Support" @@ -97,12 +138,7 @@ config DVB_NET You may want to disable the network support on embedded devices. If unsure say Y. -config VIDEO_MEDIA - tristate - default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV) - -comment "Multimedia drivers" - +comment "Media drivers" source "drivers/media/common/Kconfig" source "drivers/media/rc/Kconfig" diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index bbf4945149a9..94c6ff7a5da3 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -1,7 +1,8 @@ config MEDIA_ATTACH bool "Load and attach frontend and tuner driver modules as needed" - depends on VIDEO_MEDIA + depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT depends on MODULES + default y if !EXPERT help Remove the static dependency of DVB card drivers on all frontend modules for all possible card variants. Instead, @@ -19,15 +20,15 @@ config MEDIA_ATTACH config MEDIA_TUNER tristate - default VIDEO_MEDIA && I2C - depends on VIDEO_MEDIA && I2C + depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C + default y select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && EXPERIMENTAL - select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL + select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE @@ -47,10 +48,11 @@ config MEDIA_TUNER_CUSTOMISE menu "Customize TV tuners" visible if MEDIA_TUNER_CUSTOMISE + depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT config MEDIA_TUNER_SIMPLE tristate "Simple tuner support" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C select MEDIA_TUNER_TDA9887 default m if MEDIA_TUNER_CUSTOMISE help @@ -58,7 +60,7 @@ config MEDIA_TUNER_SIMPLE config MEDIA_TUNER_TDA8290 tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C select MEDIA_TUNER_TDA827X select MEDIA_TUNER_TDA18271 default m if MEDIA_TUNER_CUSTOMISE @@ -67,21 +69,21 @@ config MEDIA_TUNER_TDA8290 config MEDIA_TUNER_TDA827X tristate "Philips TDA827X silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A DVB-T silicon tuner module. Say Y when you want to support this tuner. config MEDIA_TUNER_TDA18271 tristate "NXP TDA18271 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A silicon tuner module. Say Y when you want to support this tuner. config MEDIA_TUNER_TDA9887 tristate "TDA 9885/6/7 analog IF demodulator" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Say Y here to include support for Philips TDA9885/6/7 @@ -89,7 +91,7 @@ config MEDIA_TUNER_TDA9887 config MEDIA_TUNER_TEA5761 tristate "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C depends on EXPERIMENTAL default m if MEDIA_TUNER_CUSTOMISE help @@ -97,63 +99,63 @@ config MEDIA_TUNER_TEA5761 config MEDIA_TUNER_TEA5767 tristate "TEA 5767 radio tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Say Y here to include support for the Philips TEA5767 radio tuner. config MEDIA_TUNER_MT20XX tristate "Microtune 2032 / 2050 tuners" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Say Y here to include support for the MT2032 / MT2050 tuner. config MEDIA_TUNER_MT2060 tristate "Microtune MT2060 silicon IF tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon IF tuner MT2060 from Microtune. config MEDIA_TUNER_MT2063 tristate "Microtune MT2063 silicon IF tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon IF tuner MT2063 from Microtune. config MEDIA_TUNER_MT2266 tristate "Microtune MT2266 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon baseband tuner MT2266 from Microtune. config MEDIA_TUNER_MT2131 tristate "Microtune MT2131 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon baseband tuner MT2131 from Microtune. config MEDIA_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon tuner QT1010 from Quantek. config MEDIA_TUNER_XC2028 tristate "XCeive xc2028/xc3028 tuners" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Say Y here to include support for the xc2028/xc3028 tuners. config MEDIA_TUNER_XC5000 tristate "Xceive XC5000 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon tuner XC5000 from Xceive. @@ -162,7 +164,7 @@ config MEDIA_TUNER_XC5000 config MEDIA_TUNER_XC4000 tristate "Xceive XC4000 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon tuner XC4000 from Xceive. @@ -171,70 +173,70 @@ config MEDIA_TUNER_XC4000 config MEDIA_TUNER_MXL5005S tristate "MaxLinear MSL5005S silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon tuner MXL5005S from MaxLinear. config MEDIA_TUNER_MXL5007T tristate "MaxLinear MxL5007T silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon tuner MxL5007T from MaxLinear. config MEDIA_TUNER_MC44S803 tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Say Y here to support the Freescale MC44S803 based tuners config MEDIA_TUNER_MAX2165 tristate "Maxim MAX2165 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help A driver for the silicon tuner MAX2165 from Maxim. config MEDIA_TUNER_TDA18218 tristate "NXP TDA18218 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help NXP TDA18218 silicon tuner driver. config MEDIA_TUNER_FC0011 tristate "Fitipower FC0011 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Fitipower FC0011 silicon tuner driver. config MEDIA_TUNER_FC0012 tristate "Fitipower FC0012 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Fitipower FC0012 silicon tuner driver. config MEDIA_TUNER_FC0013 tristate "Fitipower FC0013 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Fitipower FC0013 silicon tuner driver. config MEDIA_TUNER_TDA18212 tristate "NXP TDA18212 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help NXP TDA18212 silicon tuner driver. config MEDIA_TUNER_TUA9001 tristate "Infineon TUA 9001 silicon tuner" - depends on VIDEO_MEDIA && I2C + depends on MEDIA_SUPPORT && I2C default m if MEDIA_TUNER_CUSTOMISE help Infineon TUA 9001 silicon tuner driver. diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index b5ee3ebfcfca..ea0550eafe7d 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -90,11 +90,22 @@ struct firmware_properties { int scode_nr; }; +enum xc2028_state { + XC2028_NO_FIRMWARE = 0, + XC2028_WAITING_FIRMWARE, + XC2028_ACTIVE, + XC2028_SLEEP, + XC2028_NODEV, +}; + struct xc2028_data { struct list_head hybrid_tuner_instance_list; struct tuner_i2c_props i2c_props; __u32 frequency; + enum xc2028_state state; + const char *fname; + struct firmware_description *firm; int firm_size; __u16 firm_version; @@ -255,6 +266,21 @@ static v4l2_std_id parse_audio_std_option(void) return 0; } +static int check_device_status(struct xc2028_data *priv) +{ + switch (priv->state) { + case XC2028_NO_FIRMWARE: + case XC2028_WAITING_FIRMWARE: + return -EAGAIN; + case XC2028_ACTIVE: + case XC2028_SLEEP: + return 0; + case XC2028_NODEV: + return -ENODEV; + } + return 0; +} + static void free_firmware(struct xc2028_data *priv) { int i; @@ -270,45 +296,28 @@ static void free_firmware(struct xc2028_data *priv) priv->firm = NULL; priv->firm_size = 0; + priv->state = XC2028_NO_FIRMWARE; memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); } -static int load_all_firmwares(struct dvb_frontend *fe) +static int load_all_firmwares(struct dvb_frontend *fe, + const struct firmware *fw) { struct xc2028_data *priv = fe->tuner_priv; - const struct firmware *fw = NULL; const unsigned char *p, *endp; int rc = 0; int n, n_array; char name[33]; - char *fname; tuner_dbg("%s called\n", __func__); - if (!firmware_name[0]) - fname = priv->ctrl.fname; - else - fname = firmware_name; - - tuner_dbg("Reading firmware %s\n", fname); - rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); - if (rc < 0) { - if (rc == -ENOENT) - tuner_err("Error: firmware %s not found.\n", - fname); - else - tuner_err("Error %d while requesting firmware %s \n", - rc, fname); - - return rc; - } p = fw->data; endp = p + fw->size; if (fw->size < sizeof(name) - 1 + 2 + 2) { tuner_err("Error: firmware file %s has invalid size!\n", - fname); + priv->fname); goto corrupt; } @@ -323,7 +332,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) p += 2; tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", - n_array, fname, name, + n_array, priv->fname, name, priv->firm_version >> 8, priv->firm_version & 0xff); priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); @@ -417,9 +426,10 @@ err: free_firmware(priv); done: - release_firmware(fw); if (rc == 0) tuner_dbg("Firmware files loaded.\n"); + else + priv->state = XC2028_NODEV; return rc; } @@ -707,22 +717,15 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, { struct xc2028_data *priv = fe->tuner_priv; struct firmware_properties new_fw; - int rc = 0, retry_count = 0; + int rc, retry_count = 0; u16 version, hwmodel; v4l2_std_id std0; tuner_dbg("%s called\n", __func__); - if (!priv->firm) { - if (!priv->ctrl.fname) { - tuner_info("xc2028/3028 firmware name not set!\n"); - return -EINVAL; - } - - rc = load_all_firmwares(fe); - if (rc < 0) - return rc; - } + rc = check_device_status(priv); + if (rc < 0) + return rc; if (priv->ctrl.mts && !(type & FM)) type |= MTS; @@ -749,9 +752,13 @@ retry: printk("scode_nr %d\n", new_fw.scode_nr); } - /* No need to reload base firmware if it matches */ - if (((BASE | new_fw.type) & BASE_TYPES) == - (priv->cur_fw.type & BASE_TYPES)) { + /* + * No need to reload base firmware if it matches and if the tuner + * is not at sleep mode + */ + if ((priv->state == XC2028_ACTIVE) && + (((BASE | new_fw.type) & BASE_TYPES) == + (priv->cur_fw.type & BASE_TYPES))) { tuner_dbg("BASE firmware not changed.\n"); goto skip_base; } @@ -872,10 +879,13 @@ read_not_reliable: * 2. Tell whether BASE firmware was just changed the next time through. */ priv->cur_fw.type |= BASE; + priv->state = XC2028_ACTIVE; return 0; fail: + priv->state = XC2028_SLEEP; + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); if (retry_count < 8) { msleep(50); @@ -893,28 +903,39 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) { struct xc2028_data *priv = fe->tuner_priv; u16 frq_lock, signal = 0; - int rc; + int rc, i; tuner_dbg("%s called\n", __func__); + rc = check_device_status(priv); + if (rc < 0) + return rc; + mutex_lock(&priv->lock); /* Sync Lock Indicator */ - rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); - if (rc < 0) - goto ret; + for (i = 0; i < 3; i++) { + rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); + if (rc < 0) + goto ret; - /* Frequency is locked */ - if (frq_lock == 1) - signal = 1 << 11; + if (frq_lock) + break; + msleep(6); + } + + /* Frequency didn't lock */ + if (frq_lock == 2) + goto ret; /* Get SNR of the video signal */ rc = xc2028_get_reg(priv, XREG_SNR, &signal); if (rc < 0) goto ret; - /* Use both frq_lock and signal to generate the result */ - signal = signal || ((signal & 0x07) << 12); + /* Signal level is 3 bits only */ + + signal = ((1 << 12) - 1) | ((signal & 0x07) << 12); ret: mutex_unlock(&priv->lock); @@ -926,6 +947,49 @@ ret: return rc; } +static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc) +{ + struct xc2028_data *priv = fe->tuner_priv; + int i, rc; + u16 frq_lock = 0; + s16 afc_reg = 0; + + rc = check_device_status(priv); + if (rc < 0) + return rc; + + mutex_lock(&priv->lock); + + /* Sync Lock Indicator */ + for (i = 0; i < 3; i++) { + rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); + if (rc < 0) + goto ret; + + if (frq_lock) + break; + msleep(6); + } + + /* Frequency didn't lock */ + if (frq_lock == 2) + goto ret; + + /* Get AFC */ + rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg); + if (rc < 0) + goto ret; + + *afc = afc_reg * 15625; /* Hz */ + + tuner_dbg("AFC is %d Hz\n", *afc); + +ret: + mutex_unlock(&priv->lock); + + return rc; +} + #define DIV 15625 static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, @@ -1111,11 +1175,16 @@ static int xc2028_set_params(struct dvb_frontend *fe) u32 delsys = c->delivery_system; u32 bw = c->bandwidth_hz; struct xc2028_data *priv = fe->tuner_priv; - unsigned int type=0; + int rc; + unsigned int type = 0; u16 demod = 0; tuner_dbg("%s called\n", __func__); + rc = check_device_status(priv); + if (rc < 0) + return rc; + switch (delsys) { case SYS_DVBT: case SYS_DVBT2: @@ -1201,7 +1270,11 @@ static int xc2028_set_params(struct dvb_frontend *fe) static int xc2028_sleep(struct dvb_frontend *fe) { struct xc2028_data *priv = fe->tuner_priv; - int rc = 0; + int rc; + + rc = check_device_status(priv); + if (rc < 0) + return rc; /* Avoid firmware reload on slow devices or if PM disabled */ if (no_poweroff || priv->ctrl.disable_power_mgmt) @@ -1220,7 +1293,7 @@ static int xc2028_sleep(struct dvb_frontend *fe) else rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); - priv->cur_fw.type = 0; /* need firmware reload */ + priv->state = XC2028_SLEEP; mutex_unlock(&priv->lock); @@ -1237,8 +1310,9 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) /* only perform final cleanup if this is the last instance */ if (hybrid_tuner_report_instance_count(priv) == 1) { - kfree(priv->ctrl.fname); free_firmware(priv); + kfree(priv->ctrl.fname); + priv->ctrl.fname = NULL; } if (priv) @@ -1254,14 +1328,42 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct xc2028_data *priv = fe->tuner_priv; + int rc; tuner_dbg("%s called\n", __func__); + rc = check_device_status(priv); + if (rc < 0) + return rc; + *frequency = priv->frequency; return 0; } +static void load_firmware_cb(const struct firmware *fw, + void *context) +{ + struct dvb_frontend *fe = context; + struct xc2028_data *priv = fe->tuner_priv; + int rc; + + tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error"); + if (!fw) { + tuner_err("Could not load firmware %s.\n", priv->fname); + priv->state = XC2028_NODEV; + return; + } + + rc = load_all_firmwares(fe, fw); + + release_firmware(fw); + + if (rc < 0) + return; + priv->state = XC2028_SLEEP; +} + static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) { struct xc2028_data *priv = fe->tuner_priv; @@ -1272,21 +1374,49 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) mutex_lock(&priv->lock); + /* + * Copy the config data. + * For the firmware name, keep a local copy of the string, + * in order to avoid troubles during device release. + */ + if (priv->ctrl.fname) + kfree(priv->ctrl.fname); memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); - if (priv->ctrl.max_len < 9) - priv->ctrl.max_len = 13; - if (p->fname) { - if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) { - kfree(priv->ctrl.fname); - free_firmware(priv); - } - priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); if (priv->ctrl.fname == NULL) rc = -ENOMEM; } + /* + * If firmware name changed, frees firmware. As free_firmware will + * reset the status to NO_FIRMWARE, this forces a new request_firmware + */ + if (!firmware_name[0] && p->fname && + priv->fname && strcmp(p->fname, priv->fname)) + free_firmware(priv); + + if (priv->ctrl.max_len < 9) + priv->ctrl.max_len = 13; + + if (priv->state == XC2028_NO_FIRMWARE) { + if (!firmware_name[0]) + priv->fname = priv->ctrl.fname; + else + priv->fname = firmware_name; + + rc = request_firmware_nowait(THIS_MODULE, 1, + priv->fname, + priv->i2c_props.adap->dev.parent, + GFP_KERNEL, + fe, load_firmware_cb); + if (rc < 0) { + tuner_err("Failed to request firmware %s\n", + priv->fname); + priv->state = XC2028_NODEV; + } + priv->state = XC2028_WAITING_FIRMWARE; + } mutex_unlock(&priv->lock); return rc; @@ -1305,6 +1435,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .release = xc2028_dvb_release, .get_frequency = xc2028_get_frequency, .get_rf_strength = xc2028_signal, + .get_afc = xc2028_get_afc, .set_params = xc2028_set_params, .sleep = xc2028_sleep, }; @@ -1375,3 +1506,5 @@ MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE); +MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE); diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index dcca42ca57be..362a8d7c9738 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c @@ -210,13 +210,15 @@ struct xc5000_fw_cfg { u16 size; }; +#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" static const struct xc5000_fw_cfg xc5000a_1_6_114 = { - .name = "dvb-fe-xc5000-1.6.114.fw", + .name = XC5000A_FIRMWARE, .size = 12401, }; +#define XC5000C_FIRMWARE "dvb-fe-xc5000c-41.024.5.fw" static const struct xc5000_fw_cfg xc5000c_41_024_5 = { - .name = "dvb-fe-xc5000c-41.024.5.fw", + .name = XC5000C_FIRMWARE, .size = 16497, }; @@ -717,6 +719,12 @@ static int xc5000_set_params(struct dvb_frontend *fe) priv->freq_hz = freq - 1750000; priv->video_standard = DTV6; break; + case SYS_ISDBT: + /* All ISDB-T are currently for 6 MHz bw */ + if (!bw) + bw = 6000000; + /* fall to OFDM handling */ + case SYS_DMBTH: case SYS_DVBT: case SYS_DVBT2: dprintk(1, "%s() OFDM\n", __func__); @@ -1253,3 +1261,5 @@ EXPORT_SYMBOL(xc5000_attach); MODULE_AUTHOR("Steven Toth"); MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(XC5000A_FIRMWARE); +MODULE_FIRMWARE(XC5000C_FIRMWARE); diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c index 131b938e9e81..ebf3f05839d2 100644 --- a/drivers/media/dvb/ddbridge/ddbridge-core.c +++ b/drivers/media/dvb/ddbridge/ddbridge-core.c @@ -578,6 +578,7 @@ static int demod_attach_drxk(struct ddb_input *input) memset(&config, 0, sizeof(config)); config.microcode_name = "drxk_a3.mc"; + config.qam_demod_parameter_count = 4; config.adr = 0x29 + (input->nr & 1); fe = input->fe = dvb_attach(drxk_attach, &config, i2c); diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index e929d5697b87..7c64c09103a9 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -220,6 +220,7 @@ struct dvb_tuner_ops { #define TUNER_STATUS_STEREO 2 int (*get_status)(struct dvb_frontend *fe, u32 *status); int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); + int (*get_afc)(struct dvb_frontend *fe, s32 *afc); /** These are provided separately from set_params in order to facilitate silicon * tuners which require sophisticated tuning loops, controlling each parameter separately. */ diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 00a67326c193..39eab73b01ae 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -243,6 +243,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, if (minor == MAX_DVB_MINORS) { kfree(dvbdevfops); kfree(dvbdev); + up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); return -EINVAL; } diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index a26949336b3d..c2161565023a 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -418,9 +418,12 @@ config DVB_USB_RTL28XXU tristate "Realtek RTL28xxU DVB USB support" depends on DVB_USB && EXPERIMENTAL select DVB_RTL2830 + select DVB_RTL2832 select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_FC0013 if !MEDIA_TUNER_CUSTOMISE help Say Y here to support the Realtek RTL28xxU DVB USB receiver. diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c index 4008b9c50fbd..86861e6f86d2 100644 --- a/drivers/media/dvb/dvb-usb/az6007.c +++ b/drivers/media/dvb/dvb-usb/az6007.c @@ -590,12 +590,10 @@ static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) int ret; ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6); - memcpy(mac, st->data, sizeof(mac)); + memcpy(mac, st->data, 6); if (ret > 0) - deb_info("%s: mac is %02x:%02x:%02x:%02x:%02x:%02x\n", - __func__, mac[0], mac[1], mac[2], - mac[3], mac[4], mac[5]); + deb_info("%s: mac is %pM\n", __func__, mac); return ret; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 7a6160bf54ba..26c44818a5ab 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -100,6 +100,7 @@ #define USB_PID_CONCEPTRONIC_CTVDIGRCU 0xe397 #define USB_PID_CONEXANT_D680_DMB 0x86d6 #define USB_PID_CREATIX_CTX1921 0x1921 +#define USB_PID_DELOCK_USB2_DVBT 0xb803 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 @@ -160,6 +161,7 @@ #define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093 #define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097 #define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099 +#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1 0x00a9 #define USB_PID_TWINHAN_VP7041_COLD 0x3201 #define USB_PID_TWINHAN_VP7041_WARM 0x3202 #define USB_PID_TWINHAN_VP7020_COLD 0x3203 @@ -245,6 +247,7 @@ #define USB_PID_TERRATEC_H7_2 0x10a3 #define USB_PID_TERRATEC_T3 0x10a0 #define USB_PID_TERRATEC_T5 0x10a1 +#define USB_PID_NOXON_DAB_STICK 0x00b3 #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e #define USB_PID_PINNACLE_PCTV2000E 0x022c #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c index 41e1f5537f44..6bd0bd792437 100644 --- a/drivers/media/dvb/dvb-usb/rtl28xxu.c +++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c @@ -3,6 +3,7 @@ * * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.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 @@ -22,10 +23,13 @@ #include "rtl28xxu.h" #include "rtl2830.h" +#include "rtl2832.h" #include "qt1010.h" #include "mt2060.h" #include "mxl5005s.h" +#include "fc0012.h" +#include "fc0013.h" /* debug */ static int dvb_usb_rtl28xxu_debug; @@ -80,7 +84,7 @@ err: return ret; } -static int rtl2831_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) +static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) { struct rtl28xxu_req req; @@ -116,12 +120,12 @@ static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len) return rtl28xxu_ctrl_msg(d, &req); } -static int rtl2831_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) +static int rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val) { - return rtl2831_wr_regs(d, reg, &val, 1); + return rtl28xx_wr_regs(d, reg, &val, 1); } -static int rtl2831_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) +static int rtl28xx_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val) { return rtl2831_rd_regs(d, reg, val, 1); } @@ -308,12 +312,12 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap) */ /* GPIO direction */ - ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); + ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); if (ret) goto err; /* enable as output GPIO0, GPIO2, GPIO4 */ - ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); + ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); if (ret) goto err; @@ -381,34 +385,159 @@ err: return ret; } +static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = { + .i2c_addr = 0x10, /* 0x20 */ + .xtal = 28800000, + .if_dvbt = 0, + .tuner = TUNER_RTL2832_FC0012 +}; + +static struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = { + .i2c_addr = 0x10, /* 0x20 */ + .xtal = 28800000, + .if_dvbt = 0, + .tuner = TUNER_RTL2832_FC0013 +}; + +static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, + int cmd, int arg) +{ + int ret; + u8 val; + + deb_info("%s cmd=%d arg=%d\n", __func__, cmd, arg); + switch (cmd) { + case FC_FE_CALLBACK_VHF_ENABLE: + /* set output values */ + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); + if (ret) + goto err; + + if (arg) + val &= 0xbf; /* set GPIO6 low */ + else + val |= 0x40; /* set GPIO6 high */ + + + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); + if (ret) + goto err; + break; + default: + ret = -EINVAL; + goto err; + } + return 0; + +err: + err("%s: failed=%d\n", __func__, ret); + + return ret; +} + + +static int rtl2832u_fc0013_tuner_callback(struct dvb_usb_device *d, + int cmd, int arg) +{ + /* TODO implement*/ + return 0; +} + +static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) +{ + struct rtl28xxu_priv *priv = d->priv; + + switch (priv->tuner) { + case TUNER_RTL2832_FC0012: + return rtl2832u_fc0012_tuner_callback(d, cmd, arg); + + case TUNER_RTL2832_FC0013: + return rtl2832u_fc0013_tuner_callback(d, cmd, arg); + default: + break; + } + + return -ENODEV; +} + +static int rtl2832u_frontend_callback(void *adapter_priv, int component, + int cmd, int arg) +{ + struct i2c_adapter *adap = adapter_priv; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + switch (component) { + case DVB_FRONTEND_COMPONENT_TUNER: + return rtl2832u_tuner_callback(d, cmd, arg); + default: + break; + } + + return -EINVAL; +} + + + + static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) { int ret; struct rtl28xxu_priv *priv = adap->dev->priv; - u8 buf[1]; + struct rtl2832_config *rtl2832_config; + + u8 buf[2], val; /* open RTL2832U/RTL2832 I2C gate */ struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"}; /* close RTL2832U/RTL2832 I2C gate */ struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"}; + /* for FC0012 tuner probe */ + struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf}; + /* for FC0013 tuner probe */ + struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf}; + /* for MT2266 tuner probe */ + struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf}; /* for FC2580 tuner probe */ struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf}; + /* for MT2063 tuner probe */ + struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf}; + /* for MAX3543 tuner probe */ + struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf}; + /* for TUA9001 tuner probe */ + struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf}; + /* for MXL5007T tuner probe */ + struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf}; + /* for E4000 tuner probe */ + struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf}; + /* for TDA18272 tuner probe */ + struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; deb_info("%s:\n", __func__); - /* GPIO direction */ - ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a); + + ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_DIR, &val); if (ret) goto err; - /* enable as output GPIO0, GPIO2, GPIO4 */ - ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15); + val &= 0xbf; + + ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_DIR, val); if (ret) goto err; - ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8); + + /* enable as output GPIO3 and GPIO6*/ + ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_OUT_EN, &val); if (ret) goto err; + val |= 0x48; + + ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_EN, val); + if (ret) + goto err; + + + /* * Probe used tuner. We need to know used tuner before demod attach * since there is some demod params needed to set according to tuner. @@ -419,25 +548,108 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) if (ret) goto err; + priv->tuner = TUNER_NONE; + + /* check FC0012 ID register; reg=00 val=a1 */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012); + if (ret == 0 && buf[0] == 0xa1) { + priv->tuner = TUNER_RTL2832_FC0012; + rtl2832_config = &rtl28xxu_rtl2832_fc0012_config; + info("%s: FC0012 tuner found", __func__); + goto found; + } + + /* check FC0013 ID register; reg=00 val=a3 */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0013); + if (ret == 0 && buf[0] == 0xa3) { + priv->tuner = TUNER_RTL2832_FC0013; + rtl2832_config = &rtl28xxu_rtl2832_fc0013_config; + info("%s: FC0013 tuner found", __func__); + goto found; + } + + /* check MT2266 ID register; reg=00 val=85 */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2266); + if (ret == 0 && buf[0] == 0x85) { + priv->tuner = TUNER_RTL2832_MT2266; + /* TODO implement tuner */ + info("%s: MT2266 tuner found", __func__); + goto unsupported; + } + /* check FC2580 ID register; reg=01 val=56 */ ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580); if (ret == 0 && buf[0] == 0x56) { priv->tuner = TUNER_RTL2832_FC2580; - deb_info("%s: FC2580\n", __func__); - goto found; - } else { - deb_info("%s: FC2580 probe failed=%d - %02x\n", - __func__, ret, buf[0]); + /* TODO implement tuner */ + info("%s: FC2580 tuner found", __func__); + goto unsupported; } + /* check MT2063 ID register; reg=00 val=9e || 9c */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_mt2063); + if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) { + priv->tuner = TUNER_RTL2832_MT2063; + /* TODO implement tuner */ + info("%s: MT2063 tuner found", __func__); + goto unsupported; + } + + /* check MAX3543 ID register; reg=00 val=38 */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_max3543); + if (ret == 0 && buf[0] == 0x38) { + priv->tuner = TUNER_RTL2832_MAX3543; + /* TODO implement tuner */ + info("%s: MAX3534 tuner found", __func__); + goto unsupported; + } + + /* check TUA9001 ID register; reg=7e val=2328 */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_tua9001); + if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) { + priv->tuner = TUNER_RTL2832_TUA9001; + /* TODO implement tuner */ + info("%s: TUA9001 tuner found", __func__); + goto unsupported; + } + + /* check MXL5007R ID register; reg=d9 val=14 */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_mxl5007t); + if (ret == 0 && buf[0] == 0x14) { + priv->tuner = TUNER_RTL2832_MXL5007T; + /* TODO implement tuner */ + info("%s: MXL5007T tuner found", __func__); + goto unsupported; + } + + /* check E4000 ID register; reg=02 val=40 */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_e4000); + if (ret == 0 && buf[0] == 0x40) { + priv->tuner = TUNER_RTL2832_E4000; + /* TODO implement tuner */ + info("%s: E4000 tuner found", __func__); + goto unsupported; + } + + /* check TDA18272 ID register; reg=00 val=c760 */ + ret = rtl28xxu_ctrl_msg(adap->dev, &req_tda18272); + if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) { + priv->tuner = TUNER_RTL2832_TDA18272; + /* TODO implement tuner */ + info("%s: TDA18272 tuner found", __func__); + goto unsupported; + } + +unsupported: /* close demod I2C gate */ ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close); if (ret) goto err; /* tuner not found */ + deb_info("No compatible tuner found"); ret = -ENODEV; - goto err; + return ret; found: /* close demod I2C gate */ @@ -446,9 +658,18 @@ found: goto err; /* attach demodulator */ - /* TODO: */ + adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config, + &adap->dev->i2c_adap); + if (adap->fe_adap[0].fe == NULL) { + ret = -ENODEV; + goto err; + } + + /* set fe callbacks */ + adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback; return ret; + err: deb_info("%s: failed=%d\n", __func__, ret); return ret; @@ -531,10 +752,24 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) deb_info("%s:\n", __func__); switch (priv->tuner) { - case TUNER_RTL2832_FC2580: - /* TODO: */ - fe = NULL; + case TUNER_RTL2832_FC0012: + fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ); + + /* since fc0012 includs reading the signal strength delegate + * that to the tuner driver */ + adap->fe_adap[0].fe->ops.read_signal_strength = adap->fe_adap[0]. + fe->ops.tuner_ops.get_rf_strength; + return 0; break; + case TUNER_RTL2832_FC0013: + fe = dvb_attach(fc0013_attach, adap->fe_adap[0].fe, + &adap->dev->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ); + + /* fc0013 also supports signal strength reading */ + adap->fe_adap[0].fe->ops.read_signal_strength = adap->fe_adap[0] + .fe->ops.tuner_ops.get_rf_strength; + return 0; default: fe = NULL; err("unknown tuner=%d", priv->tuner); @@ -551,14 +786,14 @@ err: return ret; } -static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff) +static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff) { int ret; u8 buf[2], gpio; deb_info("%s: onoff=%d\n", __func__, onoff); - ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio); + ret = rtl28xx_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio); if (ret) goto err; @@ -572,11 +807,37 @@ static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff) gpio &= (~0x04); /* LED off */ } - ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio); + ret = rtl28xx_wr_reg(adap->dev, SYS_GPIO_OUT_VAL, gpio); if (ret) goto err; - ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2); + ret = rtl28xx_wr_regs(adap->dev, USB_EPA_CTL, buf, 2); + if (ret) + goto err; + + return ret; +err: + deb_info("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff) +{ + int ret; + u8 buf[2]; + + deb_info("%s: onoff=%d\n", __func__, onoff); + + + if (onoff) { + buf[0] = 0x00; + buf[1] = 0x00; + } else { + buf[0] = 0x10; /* stall EPA */ + buf[1] = 0x02; /* reset EPA */ + } + + ret = rtl28xx_wr_regs(adap->dev, USB_EPA_CTL, buf, 2); if (ret) goto err; @@ -586,7 +847,7 @@ err: return ret; } -static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff) +static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; u8 gpio, sys0; @@ -594,12 +855,12 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff) deb_info("%s: onoff=%d\n", __func__, onoff); /* demod adc */ - ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0); + ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0); if (ret) goto err; /* tuner power, read GPIOs */ - ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio); if (ret) goto err; @@ -619,12 +880,12 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff) deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio); /* demod adc */ - ret = rtl2831_wr_reg(d, SYS_SYS0, sys0); + ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0); if (ret) goto err; /* tuner power, write GPIOs */ - ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio); if (ret) goto err; @@ -634,6 +895,128 @@ err: return ret; } +static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + u8 val; + + deb_info("%s: onoff=%d\n", __func__, onoff); + + if (onoff) { + /* set output values */ + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); + if (ret) + goto err; + + val |= 0x08; + val &= 0xef; + + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); + if (ret) + goto err; + + /* demod_ctl_1 */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val); + if (ret) + goto err; + + val &= 0xef; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val); + if (ret) + goto err; + + /* demod control */ + /* PLL enable */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + + /* bit 7 to 1 */ + val |= 0x80; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + /* demod HW reset */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + /* bit 5 to 0 */ + val &= 0xdf; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + + val |= 0x20; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + mdelay(5); + + /*enable ADC_Q and ADC_I */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + + val |= 0x48; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + + } else { + /* demod_ctl_1 */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL1, &val); + if (ret) + goto err; + + val |= 0x0c; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL1, val); + if (ret) + goto err; + + /* set output values */ + ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val); + if (ret) + goto err; + + val |= 0x10; + + ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val); + if (ret) + goto err; + + /* demod control */ + ret = rtl28xx_rd_reg(d, SYS_DEMOD_CTL, &val); + if (ret) + goto err; + + val &= 0x37; + + ret = rtl28xx_wr_reg(d, SYS_DEMOD_CTL, val); + if (ret) + goto err; + + } + + return ret; +err: + deb_info("%s: failed=%d\n", __func__, ret); + return ret; +} + + static int rtl2831u_rc_query(struct dvb_usb_device *d) { int ret, i; @@ -660,7 +1043,7 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) /* init remote controller */ if (!priv->rc_active) { for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { - ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, + ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg, rc_nec_tab[i].val); if (ret) goto err; @@ -690,12 +1073,12 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) rc_keydown(d->rc_dev, rc_code, 0); - ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1); + ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1); if (ret) goto err; /* repeated intentionally to avoid extra keypress */ - ret = rtl2831_wr_reg(d, SYS_IRRC_SR, 1); + ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1); if (ret) goto err; } @@ -732,7 +1115,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) /* init remote controller */ if (!priv->rc_active) { for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) { - ret = rtl2831_wr_reg(d, rc_nec_tab[i].reg, + ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg, rc_nec_tab[i].val); if (ret) goto err; @@ -740,14 +1123,14 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) priv->rc_active = true; } - ret = rtl2831_rd_reg(d, IR_RX_IF, &buf[0]); + ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]); if (ret) goto err; if (buf[0] != 0x83) goto exit; - ret = rtl2831_rd_reg(d, IR_RX_BC, &buf[0]); + ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]); if (ret) goto err; @@ -756,9 +1139,9 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) /* TODO: pass raw IR to Kernel IR decoder */ - ret = rtl2831_wr_reg(d, IR_RX_IF, 0x03); - ret = rtl2831_wr_reg(d, IR_RX_BUF_CTRL, 0x80); - ret = rtl2831_wr_reg(d, IR_RX_CTRL, 0x80); + ret = rtl28xx_wr_reg(d, IR_RX_IF, 0x03); + ret = rtl28xx_wr_reg(d, IR_RX_BUF_CTRL, 0x80); + ret = rtl28xx_wr_reg(d, IR_RX_CTRL, 0x80); exit: return ret; @@ -771,6 +1154,9 @@ enum rtl28xxu_usb_table_entry { RTL2831U_0BDA_2831, RTL2831U_14AA_0160, RTL2831U_14AA_0161, + RTL2832U_0CCD_00A9, + RTL2832U_1F4D_B803, + RTL2832U_0CCD_00B3, }; static struct usb_device_id rtl28xxu_table[] = { @@ -783,6 +1169,12 @@ static struct usb_device_id rtl28xxu_table[] = { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)}, /* RTL2832U */ + [RTL2832U_0CCD_00A9] = { + USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1)}, + [RTL2832U_1F4D_B803] = { + USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT)}, + [RTL2832U_0CCD_00B3] = { + USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK)}, {} /* terminating entry */ }; @@ -805,7 +1197,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = { { .frontend_attach = rtl2831u_frontend_attach, .tuner_attach = rtl2831u_tuner_attach, - .streaming_ctrl = rtl28xxu_streaming_ctrl, + .streaming_ctrl = rtl2831u_streaming_ctrl, .stream = { .type = USB_BULK, .count = 6, @@ -821,7 +1213,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = { } }, - .power_ctrl = rtl28xxu_power_ctrl, + .power_ctrl = rtl2831u_power_ctrl, .rc.core = { .protocol = RC_TYPE_NEC, @@ -867,7 +1259,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = { { .frontend_attach = rtl2832u_frontend_attach, .tuner_attach = rtl2832u_tuner_attach, - .streaming_ctrl = rtl28xxu_streaming_ctrl, + .streaming_ctrl = rtl2832u_streaming_ctrl, .stream = { .type = USB_BULK, .count = 6, @@ -883,7 +1275,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = { } }, - .power_ctrl = rtl28xxu_power_ctrl, + .power_ctrl = rtl2832u_power_ctrl, .rc.core = { .protocol = RC_TYPE_NEC, @@ -896,10 +1288,25 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = { .i2c_algo = &rtl28xxu_i2c_algo, - .num_device_descs = 0, /* disabled as no support for RTL2832 */ + .num_device_descs = 3, .devices = { { - .name = "Realtek RTL2832U reference design", + .name = "Terratec Cinergy T Stick Black", + .warm_ids = { + &rtl28xxu_table[RTL2832U_0CCD_00A9], + }, + }, + { + .name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", + .warm_ids = { + &rtl28xxu_table[RTL2832U_1F4D_B803], + }, + }, + { + .name = "NOXON DAB/DAB+ USB dongle", + .warm_ids = { + &rtl28xxu_table[RTL2832U_0CCD_00B3], + }, }, } }, @@ -910,6 +1317,7 @@ static int rtl28xxu_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret, i; + u8 val; int properties_count = ARRAY_SIZE(rtl28xxu_properties); struct dvb_usb_device *d; struct usb_device *udev; @@ -954,16 +1362,25 @@ static int rtl28xxu_probe(struct usb_interface *intf, if (ret) goto err; + /* init USB endpoints */ - ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09); + ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val); + if (ret) + goto err; + + /* enable DMA and Full Packet Mode*/ + val |= 0x09; + ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val); if (ret) goto err; - ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); + /* set EPA maximum packet size to 0x0200 */ + ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4); if (ret) goto err; - ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); + /* change EPA FIFO length */ + ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4); if (ret) goto err; @@ -1007,4 +1424,5 @@ module_exit(rtl28xxu_module_exit); MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver"); MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index b98ebb264e29..a08c2152d0ee 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -1,6 +1,7 @@ config DVB_FE_CUSTOMISE bool "Customise the frontend modules to build" depends on DVB_CORE + depends on EXPERT default y if EXPERT help This allows the user to select/deselect frontend drivers for their @@ -432,6 +433,13 @@ config DVB_RTL2830 help Say Y when you want to support this frontend. +config DVB_RTL2832 + tristate "Realtek RTL2832 DVB-T" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y when you want to support this frontend. + comment "DVB-C (cable) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index cd1ac2fd5774..185bb8b51952 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -99,6 +99,7 @@ obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o obj-$(CONFIG_DVB_A8293) += a8293.o obj-$(CONFIG_DVB_TDA10071) += tda10071.o obj-$(CONFIG_DVB_RTL2830) += rtl2830.o +obj-$(CONFIG_DVB_RTL2832) += rtl2832.o obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o obj-$(CONFIG_DVB_AF9033) += af9033.o diff --git a/drivers/media/dvb/frontends/a8293.c b/drivers/media/dvb/frontends/a8293.c index bb56497e940a..cff44a389b40 100644 --- a/drivers/media/dvb/frontends/a8293.c +++ b/drivers/media/dvb/frontends/a8293.c @@ -21,24 +21,6 @@ #include "dvb_frontend.h" #include "a8293.h" -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define LOG_PREFIX "a8293" - -#undef dbg -#define dbg(f, arg...) \ - if (debug) \ - printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - - struct a8293_priv { struct i2c_adapter *i2c; const struct a8293_config *cfg; @@ -65,7 +47,8 @@ static int a8293_i2c(struct a8293_priv *priv, u8 *val, int len, bool rd) if (ret == 1) { ret = 0; } else { - warn("i2c failed=%d rd=%d", ret, rd); + dev_warn(&priv->i2c->dev, "%s: i2c failed=%d rd=%d\n", + KBUILD_MODNAME, ret, rd); ret = -EREMOTEIO; } @@ -88,7 +71,8 @@ static int a8293_set_voltage(struct dvb_frontend *fe, struct a8293_priv *priv = fe->sec_priv; int ret; - dbg("%s: fe_sec_voltage=%d", __func__, fe_sec_voltage); + dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__, + fe_sec_voltage); switch (fe_sec_voltage) { case SEC_VOLTAGE_OFF: @@ -114,14 +98,12 @@ static int a8293_set_voltage(struct dvb_frontend *fe, return ret; err: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } static void a8293_release_sec(struct dvb_frontend *fe) { - dbg("%s:", __func__); - a8293_set_voltage(fe, SEC_VOLTAGE_OFF); kfree(fe->sec_priv); @@ -154,7 +136,7 @@ struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, /* ENB=0 */ priv->reg[0] = 0x10; - ret = a8293_wr(priv, &priv->reg[1], 1); + ret = a8293_wr(priv, &priv->reg[0], 1); if (ret) goto err; @@ -164,16 +146,17 @@ struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, if (ret) goto err; - info("Allegro A8293 SEC attached."); - fe->ops.release_sec = a8293_release_sec; /* override frontend ops */ fe->ops.set_voltage = a8293_set_voltage; + dev_info(&priv->i2c->dev, "%s: Allegro A8293 SEC attached\n", + KBUILD_MODNAME); + return fe; err: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); kfree(priv); return NULL; } diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 9ca34f495009..1f3bcb5a1de8 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -2680,12 +2680,14 @@ static int dib8000_tune(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; int ret = 0; - u16 lock, value, mode = fft_to_mode(state); + u16 lock, value, mode; // we are already tuned - just resuming from suspend if (state == NULL) return -EINVAL; + mode = fft_to_mode(state); + dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000); dib8000_set_channel(state, 0, 0); diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h index 9d64e4fea066..d615d7d055a2 100644 --- a/drivers/media/dvb/frontends/drxk.h +++ b/drivers/media/dvb/frontends/drxk.h @@ -20,6 +20,14 @@ * means that 1=DVBC, 0 = DVBT. Zero means the opposite. * @mpeg_out_clk_strength: DRXK Mpeg output clock drive strength. * @microcode_name: Name of the firmware file with the microcode + * @qam_demod_parameter_count: The number of parameters used for the command + * to set the demodulator parameters. All + * firmwares are using the 2-parameter commmand. + * An exception is the "drxk_a3.mc" firmware, + * which uses the 4-parameter command. + * A value of 0 (default) or lower indicates that + * the correct number of parameters will be + * automatically detected. * * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is * UIO-3. @@ -38,7 +46,8 @@ struct drxk_config { u8 mpeg_out_clk_strength; int chunk_size; - const char *microcode_name; + const char *microcode_name; + int qam_demod_parameter_count; }; #if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \ diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c index 60b868faeacf..1ab8154542da 100644 --- a/drivers/media/dvb/frontends/drxk_hard.c +++ b/drivers/media/dvb/frontends/drxk_hard.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include <linux/firmware.h> #include <linux/i2c.h> +#include <linux/hardirq.h> #include <asm/div64.h> #include "dvb_frontend.h" @@ -308,16 +309,42 @@ static u32 Log10Times100(u32 x) /* I2C **********************************************************************/ /****************************************************************************/ -static int i2c_read1(struct i2c_adapter *adapter, u8 adr, u8 *val) +static int drxk_i2c_lock(struct drxk_state *state) +{ + i2c_lock_adapter(state->i2c); + state->drxk_i2c_exclusive_lock = true; + + return 0; +} + +static void drxk_i2c_unlock(struct drxk_state *state) +{ + if (!state->drxk_i2c_exclusive_lock) + return; + + i2c_unlock_adapter(state->i2c); + state->drxk_i2c_exclusive_lock = false; +} + +static int drxk_i2c_transfer(struct drxk_state *state, struct i2c_msg *msgs, + unsigned len) +{ + if (state->drxk_i2c_exclusive_lock) + return __i2c_transfer(state->i2c, msgs, len); + else + return i2c_transfer(state->i2c, msgs, len); +} + +static int i2c_read1(struct drxk_state *state, u8 adr, u8 *val) { struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD, .buf = val, .len = 1} }; - return i2c_transfer(adapter, msgs, 1); + return drxk_i2c_transfer(state, msgs, 1); } -static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +static int i2c_write(struct drxk_state *state, u8 adr, u8 *data, int len) { int status; struct i2c_msg msg = { @@ -330,7 +357,7 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) printk(KERN_CONT " %02x", data[i]); printk(KERN_CONT "\n"); } - status = i2c_transfer(adap, &msg, 1); + status = drxk_i2c_transfer(state, &msg, 1); if (status >= 0 && status != 1) status = -EIO; @@ -340,7 +367,7 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) return status; } -static int i2c_read(struct i2c_adapter *adap, +static int i2c_read(struct drxk_state *state, u8 adr, u8 *msg, int len, u8 *answ, int alen) { int status; @@ -351,7 +378,7 @@ static int i2c_read(struct i2c_adapter *adap, .buf = answ, .len = alen} }; - status = i2c_transfer(adap, msgs, 2); + status = drxk_i2c_transfer(state, msgs, 2); if (status != 2) { if (debug > 2) printk(KERN_CONT ": ERROR!\n"); @@ -394,7 +421,7 @@ static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags) len = 2; } dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags); - status = i2c_read(state->i2c, adr, mm1, len, mm2, 2); + status = i2c_read(state, adr, mm1, len, mm2, 2); if (status < 0) return status; if (data) @@ -428,7 +455,7 @@ static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags) len = 2; } dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags); - status = i2c_read(state->i2c, adr, mm1, len, mm2, 4); + status = i2c_read(state, adr, mm1, len, mm2, 4); if (status < 0) return status; if (data) @@ -464,7 +491,7 @@ static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags) mm[len + 1] = (data >> 8) & 0xff; dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags); - return i2c_write(state->i2c, adr, mm, len + 2); + return i2c_write(state, adr, mm, len + 2); } static int write16(struct drxk_state *state, u32 reg, u16 data) @@ -495,7 +522,7 @@ static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags) mm[len + 3] = (data >> 24) & 0xff; dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags); - return i2c_write(state->i2c, adr, mm, len + 4); + return i2c_write(state, adr, mm, len + 4); } static int write32(struct drxk_state *state, u32 reg, u32 data) @@ -542,7 +569,7 @@ static int write_block(struct drxk_state *state, u32 Address, printk(KERN_CONT " %02x", pBlock[i]); printk(KERN_CONT "\n"); } - status = i2c_write(state->i2c, state->demod_address, + status = i2c_write(state, state->demod_address, &state->Chunk[0], Chunk + AdrLength); if (status < 0) { printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n", @@ -568,17 +595,17 @@ int PowerUpDevice(struct drxk_state *state) dprintk(1, "\n"); - status = i2c_read1(state->i2c, state->demod_address, &data); + status = i2c_read1(state, state->demod_address, &data); if (status < 0) { do { data = 0; - status = i2c_write(state->i2c, state->demod_address, + status = i2c_write(state, state->demod_address, &data, 1); msleep(10); retryCount++; if (status < 0) continue; - status = i2c_read1(state->i2c, state->demod_address, + status = i2c_read1(state, state->demod_address, &data); } while (status < 0 && (retryCount < DRXK_MAX_RETRIES_POWERUP)); @@ -932,7 +959,7 @@ static int GetDeviceCapabilities(struct drxk_state *state) if (status < 0) goto error; -printk(KERN_ERR "drxk: status = 0x%08x\n", sioTopJtagidLo); + printk(KERN_INFO "drxk: status = 0x%08x\n", sioTopJtagidLo); /* driver 0.9.0 */ switch ((sioTopJtagidLo >> 29) & 0xF) { @@ -2824,7 +2851,7 @@ static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge) dprintk(1, "\n"); if (state->m_DrxkState == DRXK_UNINITIALIZED) - goto error; + return 0; if (state->m_DrxkState == DRXK_POWERED_DOWN) goto error; @@ -2977,7 +3004,7 @@ static int ADCSynchronization(struct drxk_state *state) status = read16(state, IQM_AF_CLKNEG__A, &clkNeg); if (status < 0) goto error; - if ((clkNeg | IQM_AF_CLKNEG_CLKNEGDATA__M) == + if ((clkNeg & IQM_AF_CLKNEG_CLKNEGDATA__M) == IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) { clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M)); clkNeg |= @@ -5361,7 +5388,7 @@ static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus) SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2, Result); if (status < 0) - printk(KERN_ERR "drxk: %s status = %08x\n", __func__, status); + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) { /* 0x0000 NOT LOCKED */ @@ -5388,12 +5415,67 @@ static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus) #define QAM_LOCKRANGE__M 0x10 #define QAM_LOCKRANGE_NORMAL 0x10 +static int QAMDemodulatorCommand(struct drxk_state *state, + int numberOfParameters) +{ + int status; + u16 cmdResult; + u16 setParamParameters[4] = { 0, 0, 0, 0 }; + + setParamParameters[0] = state->m_Constellation; /* modulation */ + setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ + + if (numberOfParameters == 2) { + u16 setEnvParameters[1] = { 0 }; + + if (state->m_OperationMode == OM_QAM_ITU_C) + setEnvParameters[0] = QAM_TOP_ANNEX_C; + else + setEnvParameters[0] = QAM_TOP_ANNEX_A; + + status = scu_command(state, + SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, + 1, setEnvParameters, 1, &cmdResult); + if (status < 0) + goto error; + + status = scu_command(state, + SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, + numberOfParameters, setParamParameters, + 1, &cmdResult); + } else if (numberOfParameters == 4) { + if (state->m_OperationMode == OM_QAM_ITU_C) + setParamParameters[2] = QAM_TOP_ANNEX_C; + else + setParamParameters[2] = QAM_TOP_ANNEX_A; + + setParamParameters[3] |= (QAM_MIRROR_AUTO_ON); + /* Env parameters */ + /* check for LOCKRANGE Extented */ + /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */ + + status = scu_command(state, + SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, + numberOfParameters, setParamParameters, + 1, &cmdResult); + } else { + printk(KERN_WARNING "drxk: Unknown QAM demodulator parameter " + "count %d\n", numberOfParameters); + } + +error: + if (status < 0) + printk(KERN_WARNING "drxk: Warning %d on %s\n", + status, __func__); + return status; +} + static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, s32 tunerFreqOffset) { int status; - u16 setParamParameters[4] = { 0, 0, 0, 0 }; u16 cmdResult; + int qamDemodParamCount = state->qam_demod_parameter_count; dprintk(1, "\n"); /* @@ -5445,34 +5527,42 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, } if (status < 0) goto error; - setParamParameters[0] = state->m_Constellation; /* modulation */ - setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ - if (state->m_OperationMode == OM_QAM_ITU_C) - setParamParameters[2] = QAM_TOP_ANNEX_C; - else - setParamParameters[2] = QAM_TOP_ANNEX_A; - setParamParameters[3] |= (QAM_MIRROR_AUTO_ON); - /* Env parameters */ - /* check for LOCKRANGE Extented */ - /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */ - status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 4, setParamParameters, 1, &cmdResult); - if (status < 0) { - /* Fall-back to the simpler call */ - if (state->m_OperationMode == OM_QAM_ITU_C) - setParamParameters[0] = QAM_TOP_ANNEX_C; - else - setParamParameters[0] = QAM_TOP_ANNEX_A; - status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 1, setParamParameters, 1, &cmdResult); - if (status < 0) - goto error; + /* Use the 4-parameter if it's requested or we're probing for + * the correct command. */ + if (state->qam_demod_parameter_count == 4 + || !state->qam_demod_parameter_count) { + qamDemodParamCount = 4; + status = QAMDemodulatorCommand(state, qamDemodParamCount); + } - setParamParameters[0] = state->m_Constellation; /* modulation */ - setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ - status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult); + /* Use the 2-parameter command if it was requested or if we're + * probing for the correct command and the 4-parameter command + * failed. */ + if (state->qam_demod_parameter_count == 2 + || (!state->qam_demod_parameter_count && status < 0)) { + qamDemodParamCount = 2; + status = QAMDemodulatorCommand(state, qamDemodParamCount); } - if (status < 0) + + if (status < 0) { + dprintk(1, "Could not set demodulator parameters. Make " + "sure qam_demod_parameter_count (%d) is correct for " + "your firmware (%s).\n", + state->qam_demod_parameter_count, + state->microcode_name); goto error; + } else if (!state->qam_demod_parameter_count) { + dprintk(1, "Auto-probing the correct QAM demodulator command " + "parameters was successful - using %d parameters.\n", + qamDemodParamCount); + + /* + * One of our commands was successful. We don't need to + * auto-probe anymore, now that we got the correct command. + */ + state->qam_demod_parameter_count = qamDemodParamCount; + } /* * STEP 3: enable the system in a mode where the ADC provides valid @@ -5968,34 +6058,15 @@ error: return status; } -static int load_microcode(struct drxk_state *state, const char *mc_name) -{ - const struct firmware *fw = NULL; - int err = 0; - - dprintk(1, "\n"); - - err = request_firmware(&fw, mc_name, state->i2c->dev.parent); - if (err < 0) { - printk(KERN_ERR - "drxk: Could not load firmware file %s.\n", mc_name); - printk(KERN_INFO - "drxk: Copy %s to your hotplug directory!\n", mc_name); - return err; - } - err = DownloadMicrocode(state, fw->data, fw->size); - release_firmware(fw); - return err; -} - static int init_drxk(struct drxk_state *state) { - int status = 0; + int status = 0, n = 0; enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM; u16 driverVersion; dprintk(1, "\n"); if ((state->m_DrxkState == DRXK_UNINITIALIZED)) { + drxk_i2c_lock(state); status = PowerUpDevice(state); if (status < 0) goto error; @@ -6073,8 +6144,12 @@ static int init_drxk(struct drxk_state *state) if (status < 0) goto error; - if (state->microcode_name) - load_microcode(state, state->microcode_name); + if (state->fw) { + status = DownloadMicrocode(state, state->fw->data, + state->fw->size); + if (status < 0) + goto error; + } /* disable token-ring bus through OFDM block for possible ucode upload */ status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF); @@ -6167,19 +6242,71 @@ static int init_drxk(struct drxk_state *state) state->m_DrxkState = DRXK_POWERED_DOWN; } else state->m_DrxkState = DRXK_STOPPED; + + /* Initialize the supported delivery systems */ + n = 0; + if (state->m_hasDVBC) { + state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A; + state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C; + strlcat(state->frontend.ops.info.name, " DVB-C", + sizeof(state->frontend.ops.info.name)); + } + if (state->m_hasDVBT) { + state->frontend.ops.delsys[n++] = SYS_DVBT; + strlcat(state->frontend.ops.info.name, " DVB-T", + sizeof(state->frontend.ops.info.name)); + } + drxk_i2c_unlock(state); } error: - if (status < 0) + if (status < 0) { + state->m_DrxkState = DRXK_NO_DEV; + drxk_i2c_unlock(state); printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + } return status; } +static void load_firmware_cb(const struct firmware *fw, + void *context) +{ + struct drxk_state *state = context; + + dprintk(1, ": %s\n", fw ? "firmware loaded" : "firmware not loaded"); + if (!fw) { + printk(KERN_ERR + "drxk: Could not load firmware file %s.\n", + state->microcode_name); + printk(KERN_INFO + "drxk: Copy %s to your hotplug directory!\n", + state->microcode_name); + state->microcode_name = NULL; + + /* + * As firmware is now load asynchronous, it is not possible + * anymore to fail at frontend attach. We might silently + * return here, and hope that the driver won't crash. + * We might also change all DVB callbacks to return -ENODEV + * if the device is not initialized. + * As the DRX-K devices have their own internal firmware, + * let's just hope that it will match a firmware revision + * compatible with this driver and proceed. + */ + } + state->fw = fw; + + init_drxk(state); +} + static void drxk_release(struct dvb_frontend *fe) { struct drxk_state *state = fe->demodulator_priv; dprintk(1, "\n"); + if (state->fw) + release_firmware(state->fw); + kfree(state); } @@ -6188,6 +6315,12 @@ static int drxk_sleep(struct dvb_frontend *fe) struct drxk_state *state = fe->demodulator_priv; dprintk(1, "\n"); + + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + if (state->m_DrxkState == DRXK_UNINITIALIZED) + return 0; + ShutDown(state); return 0; } @@ -6196,7 +6329,11 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct drxk_state *state = fe->demodulator_priv; - dprintk(1, "%s\n", enable ? "enable" : "disable"); + dprintk(1, ": %s\n", enable ? "enable" : "disable"); + + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + return ConfigureI2CBridge(state, enable ? true : false); } @@ -6209,6 +6346,12 @@ static int drxk_set_parameters(struct dvb_frontend *fe) dprintk(1, "\n"); + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + + if (state->m_DrxkState == DRXK_UNINITIALIZED) + return -EAGAIN; + if (!fe->ops.tuner_ops.get_if_frequency) { printk(KERN_ERR "drxk: Error: get_if_frequency() not defined at tuner. Can't work without it!\n"); @@ -6262,6 +6405,12 @@ static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) u32 stat; dprintk(1, "\n"); + + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + if (state->m_DrxkState == DRXK_UNINITIALIZED) + return -EAGAIN; + *status = 0; GetLockStatus(state, &stat, 0); if (stat == MPEG_LOCK) @@ -6275,8 +6424,15 @@ static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber) { + struct drxk_state *state = fe->demodulator_priv; + dprintk(1, "\n"); + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + if (state->m_DrxkState == DRXK_UNINITIALIZED) + return -EAGAIN; + *ber = 0; return 0; } @@ -6288,6 +6444,12 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe, u32 val = 0; dprintk(1, "\n"); + + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + if (state->m_DrxkState == DRXK_UNINITIALIZED) + return -EAGAIN; + ReadIFAgc(state, &val); *strength = val & 0xffff; return 0; @@ -6299,6 +6461,12 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr) s32 snr2; dprintk(1, "\n"); + + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + if (state->m_DrxkState == DRXK_UNINITIALIZED) + return -EAGAIN; + GetSignalToNoise(state, &snr2); *snr = snr2 & 0xffff; return 0; @@ -6310,6 +6478,12 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) u16 err; dprintk(1, "\n"); + + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + if (state->m_DrxkState == DRXK_UNINITIALIZED) + return -EAGAIN; + DVBTQAMGetAccPktErr(state, &err); *ucblocks = (u32) err; return 0; @@ -6318,9 +6492,16 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *sets) { + struct drxk_state *state = fe->demodulator_priv; struct dtv_frontend_properties *p = &fe->dtv_property_cache; dprintk(1, "\n"); + + if (state->m_DrxkState == DRXK_NO_DEV) + return -ENODEV; + if (state->m_DrxkState == DRXK_UNINITIALIZED) + return -EAGAIN; + switch (p->delivery_system) { case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_C: @@ -6371,10 +6552,9 @@ static struct dvb_frontend_ops drxk_ops = { struct dvb_frontend *drxk_attach(const struct drxk_config *config, struct i2c_adapter *i2c) { - int n; - struct drxk_state *state = NULL; u8 adr = config->adr; + int status; dprintk(1, "\n"); state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL); @@ -6385,6 +6565,7 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, state->demod_address = adr; state->single_master = config->single_master; state->microcode_name = config->microcode_name; + state->qam_demod_parameter_count = config->qam_demod_parameter_count; state->no_i2c_bridge = config->no_i2c_bridge; state->antenna_gpio = config->antenna_gpio; state->antenna_dvbt = config->antenna_dvbt; @@ -6425,22 +6606,21 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, state->frontend.demodulator_priv = state; init_state(state); - if (init_drxk(state) < 0) - goto error; - /* Initialize the supported delivery systems */ - n = 0; - if (state->m_hasDVBC) { - state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A; - state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C; - strlcat(state->frontend.ops.info.name, " DVB-C", - sizeof(state->frontend.ops.info.name)); - } - if (state->m_hasDVBT) { - state->frontend.ops.delsys[n++] = SYS_DVBT; - strlcat(state->frontend.ops.info.name, " DVB-T", - sizeof(state->frontend.ops.info.name)); - } + /* Load firmware and initialize DRX-K */ + if (state->microcode_name) { + status = request_firmware_nowait(THIS_MODULE, 1, + state->microcode_name, + state->i2c->dev.parent, + GFP_KERNEL, + state, load_firmware_cb); + if (status < 0) { + printk(KERN_ERR + "drxk: failed to request a firmware\n"); + return NULL; + } + } else if (init_drxk(state) < 0) + goto error; printk(KERN_INFO "drxk: frontend initialized.\n"); return &state->frontend; diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h index 4bbf841de83a..6bb9fc4a7b96 100644 --- a/drivers/media/dvb/frontends/drxk_hard.h +++ b/drivers/media/dvb/frontends/drxk_hard.h @@ -94,7 +94,15 @@ enum DRXPowerMode { enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF }; -enum EDrxkState { DRXK_UNINITIALIZED = 0, DRXK_STOPPED, DRXK_DTV_STARTED, DRXK_ATV_STARTED, DRXK_POWERED_DOWN }; +enum EDrxkState { + DRXK_UNINITIALIZED = 0, + DRXK_STOPPED, + DRXK_DTV_STARTED, + DRXK_ATV_STARTED, + DRXK_POWERED_DOWN, + DRXK_NO_DEV /* If drxk init failed */ +}; + enum EDrxkCoefArrayIndex { DRXK_COEF_IDX_MN = 0, DRXK_COEF_IDX_FM , @@ -325,6 +333,9 @@ struct drxk_state { enum DRXPowerMode m_currentPowerMode; + /* when true, avoids other devices to use the I2C bus */ + bool drxk_i2c_exclusive_lock; + /* * Configurable parameters at the driver. They stores the values found * at struct drxk_config. @@ -338,7 +349,11 @@ struct drxk_state { bool antenna_dvbt; u16 antenna_gpio; + /* Firmware */ const char *microcode_name; + struct completion fw_wait_load; + const struct firmware *fw; + int qam_demod_parameter_count; }; #define NEVER_LOCK 0 diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index 568363a10a31..c2ea2749ebed 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -40,6 +40,8 @@ static int debug; static int fake_signal_str = 1; +#define LGS8GXX_FIRMWARE "lgs8g75.fw" + module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); @@ -592,7 +594,7 @@ static int lgs8g75_init_data(struct lgs8gxx_state *priv) int rc; int i; - rc = request_firmware(&fw, "lgs8g75.fw", &priv->i2c->dev); + rc = request_firmware(&fw, LGS8GXX_FIRMWARE, &priv->i2c->dev); if (rc) return rc; @@ -1070,3 +1072,4 @@ EXPORT_SYMBOL(lgs8gxx_attach); MODULE_DESCRIPTION("Legend Silicon LGS8913/LGS8GXX DMB-TH demodulator driver"); MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(LGS8GXX_FIRMWARE); diff --git a/drivers/media/dvb/frontends/rtl2832.c b/drivers/media/dvb/frontends/rtl2832.c new file mode 100644 index 000000000000..28269ccaeab7 --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2832.c @@ -0,0 +1,789 @@ +/* + * Realtek RTL2832 DVB-T demodulator driver + * + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "rtl2832_priv.h" +#include <linux/bitops.h> + +int rtl2832_debug; +module_param_named(debug, rtl2832_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +#define REG_MASK(b) (BIT(b + 1) - 1) + +static const struct rtl2832_reg_entry registers[] = { + [DVBT_SOFT_RST] = {0x1, 0x1, 2, 2}, + [DVBT_IIC_REPEAT] = {0x1, 0x1, 3, 3}, + [DVBT_TR_WAIT_MIN_8K] = {0x1, 0x88, 11, 2}, + [DVBT_RSD_BER_FAIL_VAL] = {0x1, 0x8f, 15, 0}, + [DVBT_EN_BK_TRK] = {0x1, 0xa6, 7, 7}, + [DVBT_AD_EN_REG] = {0x0, 0x8, 7, 7}, + [DVBT_AD_EN_REG1] = {0x0, 0x8, 6, 6}, + [DVBT_EN_BBIN] = {0x1, 0xb1, 0, 0}, + [DVBT_MGD_THD0] = {0x1, 0x95, 7, 0}, + [DVBT_MGD_THD1] = {0x1, 0x96, 7, 0}, + [DVBT_MGD_THD2] = {0x1, 0x97, 7, 0}, + [DVBT_MGD_THD3] = {0x1, 0x98, 7, 0}, + [DVBT_MGD_THD4] = {0x1, 0x99, 7, 0}, + [DVBT_MGD_THD5] = {0x1, 0x9a, 7, 0}, + [DVBT_MGD_THD6] = {0x1, 0x9b, 7, 0}, + [DVBT_MGD_THD7] = {0x1, 0x9c, 7, 0}, + [DVBT_EN_CACQ_NOTCH] = {0x1, 0x61, 4, 4}, + [DVBT_AD_AV_REF] = {0x0, 0x9, 6, 0}, + [DVBT_REG_PI] = {0x0, 0xa, 2, 0}, + [DVBT_PIP_ON] = {0x0, 0x21, 3, 3}, + [DVBT_SCALE1_B92] = {0x2, 0x92, 7, 0}, + [DVBT_SCALE1_B93] = {0x2, 0x93, 7, 0}, + [DVBT_SCALE1_BA7] = {0x2, 0xa7, 7, 0}, + [DVBT_SCALE1_BA9] = {0x2, 0xa9, 7, 0}, + [DVBT_SCALE1_BAA] = {0x2, 0xaa, 7, 0}, + [DVBT_SCALE1_BAB] = {0x2, 0xab, 7, 0}, + [DVBT_SCALE1_BAC] = {0x2, 0xac, 7, 0}, + [DVBT_SCALE1_BB0] = {0x2, 0xb0, 7, 0}, + [DVBT_SCALE1_BB1] = {0x2, 0xb1, 7, 0}, + [DVBT_KB_P1] = {0x1, 0x64, 3, 1}, + [DVBT_KB_P2] = {0x1, 0x64, 6, 4}, + [DVBT_KB_P3] = {0x1, 0x65, 2, 0}, + [DVBT_OPT_ADC_IQ] = {0x0, 0x6, 5, 4}, + [DVBT_AD_AVI] = {0x0, 0x9, 1, 0}, + [DVBT_AD_AVQ] = {0x0, 0x9, 3, 2}, + [DVBT_K1_CR_STEP12] = {0x2, 0xad, 9, 4}, + [DVBT_TRK_KS_P2] = {0x1, 0x6f, 2, 0}, + [DVBT_TRK_KS_I2] = {0x1, 0x70, 5, 3}, + [DVBT_TR_THD_SET2] = {0x1, 0x72, 3, 0}, + [DVBT_TRK_KC_P2] = {0x1, 0x73, 5, 3}, + [DVBT_TRK_KC_I2] = {0x1, 0x75, 2, 0}, + [DVBT_CR_THD_SET2] = {0x1, 0x76, 7, 6}, + [DVBT_PSET_IFFREQ] = {0x1, 0x19, 21, 0}, + [DVBT_SPEC_INV] = {0x1, 0x15, 0, 0}, + [DVBT_RSAMP_RATIO] = {0x1, 0x9f, 27, 2}, + [DVBT_CFREQ_OFF_RATIO] = {0x1, 0x9d, 23, 4}, + [DVBT_FSM_STAGE] = {0x3, 0x51, 6, 3}, + [DVBT_RX_CONSTEL] = {0x3, 0x3c, 3, 2}, + [DVBT_RX_HIER] = {0x3, 0x3c, 6, 4}, + [DVBT_RX_C_RATE_LP] = {0x3, 0x3d, 2, 0}, + [DVBT_RX_C_RATE_HP] = {0x3, 0x3d, 5, 3}, + [DVBT_GI_IDX] = {0x3, 0x51, 1, 0}, + [DVBT_FFT_MODE_IDX] = {0x3, 0x51, 2, 2}, + [DVBT_RSD_BER_EST] = {0x3, 0x4e, 15, 0}, + [DVBT_CE_EST_EVM] = {0x4, 0xc, 15, 0}, + [DVBT_RF_AGC_VAL] = {0x3, 0x5b, 13, 0}, + [DVBT_IF_AGC_VAL] = {0x3, 0x59, 13, 0}, + [DVBT_DAGC_VAL] = {0x3, 0x5, 7, 0}, + [DVBT_SFREQ_OFF] = {0x3, 0x18, 13, 0}, + [DVBT_CFREQ_OFF] = {0x3, 0x5f, 17, 0}, + [DVBT_POLAR_RF_AGC] = {0x0, 0xe, 1, 1}, + [DVBT_POLAR_IF_AGC] = {0x0, 0xe, 0, 0}, + [DVBT_AAGC_HOLD] = {0x1, 0x4, 5, 5}, + [DVBT_EN_RF_AGC] = {0x1, 0x4, 6, 6}, + [DVBT_EN_IF_AGC] = {0x1, 0x4, 7, 7}, + [DVBT_IF_AGC_MIN] = {0x1, 0x8, 7, 0}, + [DVBT_IF_AGC_MAX] = {0x1, 0x9, 7, 0}, + [DVBT_RF_AGC_MIN] = {0x1, 0xa, 7, 0}, + [DVBT_RF_AGC_MAX] = {0x1, 0xb, 7, 0}, + [DVBT_IF_AGC_MAN] = {0x1, 0xc, 6, 6}, + [DVBT_IF_AGC_MAN_VAL] = {0x1, 0xc, 13, 0}, + [DVBT_RF_AGC_MAN] = {0x1, 0xe, 6, 6}, + [DVBT_RF_AGC_MAN_VAL] = {0x1, 0xe, 13, 0}, + [DVBT_DAGC_TRG_VAL] = {0x1, 0x12, 7, 0}, + [DVBT_AGC_TARG_VAL_0] = {0x1, 0x2, 0, 0}, + [DVBT_AGC_TARG_VAL_8_1] = {0x1, 0x3, 7, 0}, + [DVBT_AAGC_LOOP_GAIN] = {0x1, 0xc7, 5, 1}, + [DVBT_LOOP_GAIN2_3_0] = {0x1, 0x4, 4, 1}, + [DVBT_LOOP_GAIN2_4] = {0x1, 0x5, 7, 7}, + [DVBT_LOOP_GAIN3] = {0x1, 0xc8, 4, 0}, + [DVBT_VTOP1] = {0x1, 0x6, 5, 0}, + [DVBT_VTOP2] = {0x1, 0xc9, 5, 0}, + [DVBT_VTOP3] = {0x1, 0xca, 5, 0}, + [DVBT_KRF1] = {0x1, 0xcb, 7, 0}, + [DVBT_KRF2] = {0x1, 0x7, 7, 0}, + [DVBT_KRF3] = {0x1, 0xcd, 7, 0}, + [DVBT_KRF4] = {0x1, 0xce, 7, 0}, + [DVBT_EN_GI_PGA] = {0x1, 0xe5, 0, 0}, + [DVBT_THD_LOCK_UP] = {0x1, 0xd9, 8, 0}, + [DVBT_THD_LOCK_DW] = {0x1, 0xdb, 8, 0}, + [DVBT_THD_UP1] = {0x1, 0xdd, 7, 0}, + [DVBT_THD_DW1] = {0x1, 0xde, 7, 0}, + [DVBT_INTER_CNT_LEN] = {0x1, 0xd8, 3, 0}, + [DVBT_GI_PGA_STATE] = {0x1, 0xe6, 3, 3}, + [DVBT_EN_AGC_PGA] = {0x1, 0xd7, 0, 0}, + [DVBT_CKOUTPAR] = {0x1, 0x7b, 5, 5}, + [DVBT_CKOUT_PWR] = {0x1, 0x7b, 6, 6}, + [DVBT_SYNC_DUR] = {0x1, 0x7b, 7, 7}, + [DVBT_ERR_DUR] = {0x1, 0x7c, 0, 0}, + [DVBT_SYNC_LVL] = {0x1, 0x7c, 1, 1}, + [DVBT_ERR_LVL] = {0x1, 0x7c, 2, 2}, + [DVBT_VAL_LVL] = {0x1, 0x7c, 3, 3}, + [DVBT_SERIAL] = {0x1, 0x7c, 4, 4}, + [DVBT_SER_LSB] = {0x1, 0x7c, 5, 5}, + [DVBT_CDIV_PH0] = {0x1, 0x7d, 3, 0}, + [DVBT_CDIV_PH1] = {0x1, 0x7d, 7, 4}, + [DVBT_MPEG_IO_OPT_2_2] = {0x0, 0x6, 7, 7}, + [DVBT_MPEG_IO_OPT_1_0] = {0x0, 0x7, 7, 6}, + [DVBT_CKOUTPAR_PIP] = {0x0, 0xb7, 4, 4}, + [DVBT_CKOUT_PWR_PIP] = {0x0, 0xb7, 3, 3}, + [DVBT_SYNC_LVL_PIP] = {0x0, 0xb7, 2, 2}, + [DVBT_ERR_LVL_PIP] = {0x0, 0xb7, 1, 1}, + [DVBT_VAL_LVL_PIP] = {0x0, 0xb7, 0, 0}, + [DVBT_CKOUTPAR_PID] = {0x0, 0xb9, 4, 4}, + [DVBT_CKOUT_PWR_PID] = {0x0, 0xb9, 3, 3}, + [DVBT_SYNC_LVL_PID] = {0x0, 0xb9, 2, 2}, + [DVBT_ERR_LVL_PID] = {0x0, 0xb9, 1, 1}, + [DVBT_VAL_LVL_PID] = {0x0, 0xb9, 0, 0}, + [DVBT_SM_PASS] = {0x1, 0x93, 11, 0}, + [DVBT_AD7_SETTING] = {0x0, 0x11, 15, 0}, + [DVBT_RSSI_R] = {0x3, 0x1, 6, 0}, + [DVBT_ACI_DET_IND] = {0x3, 0x12, 0, 0}, + [DVBT_REG_MON] = {0x0, 0xd, 1, 0}, + [DVBT_REG_MONSEL] = {0x0, 0xd, 2, 2}, + [DVBT_REG_GPE] = {0x0, 0xd, 7, 7}, + [DVBT_REG_GPO] = {0x0, 0x10, 0, 0}, + [DVBT_REG_4MSEL] = {0x0, 0x13, 0, 0}, +}; + +/* write multiple hardware registers */ +static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) +{ + int ret; + u8 buf[1+len]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = 1+len, + .buf = buf, + } + }; + + buf[0] = reg; + memcpy(&buf[1], val, len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + return ret; +} + +/* read multiple hardware registers */ +static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) +{ + int ret; + struct i2c_msg msg[2] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = 1, + .buf = ®, + }, { + .addr = priv->cfg.i2c_addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + ret = 0; + } else { + warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); + ret = -EREMOTEIO; +} +return ret; +} + +/* write multiple registers */ +static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, + int len) +{ + int ret; + + + /* switch bank if needed */ + if (page != priv->page) { + ret = rtl2832_wr(priv, 0x00, &page, 1); + if (ret) + return ret; + + priv->page = page; +} + +return rtl2832_wr(priv, reg, val, len); +} + +/* read multiple registers */ +static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, + int len) +{ + int ret; + + /* switch bank if needed */ + if (page != priv->page) { + ret = rtl2832_wr(priv, 0x00, &page, 1); + if (ret) + return ret; + + priv->page = page; + } + + return rtl2832_rd(priv, reg, val, len); +} + +#if 0 /* currently not used */ +/* write single register */ +static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val) +{ + return rtl2832_wr_regs(priv, reg, page, &val, 1); +} +#endif + +/* read single register */ +static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val) +{ + return rtl2832_rd_regs(priv, reg, page, val, 1); +} + +int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val) +{ + int ret; + + u8 reg_start_addr; + u8 msb, lsb; + u8 page; + u8 reading[4]; + u32 reading_tmp; + int i; + + u8 len; + u32 mask; + + reg_start_addr = registers[reg].start_address; + msb = registers[reg].msb; + lsb = registers[reg].lsb; + page = registers[reg].page; + + len = (msb >> 3) + 1; + mask = REG_MASK(msb - lsb); + + ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len); + if (ret) + goto err; + + reading_tmp = 0; + for (i = 0; i < len; i++) + reading_tmp |= reading[i] << ((len - 1 - i) * 8); + + *val = (reading_tmp >> lsb) & mask; + + return ret; + +err: + dbg("%s: failed=%d", __func__, ret); + return ret; + +} + +int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val) +{ + int ret, i; + u8 len; + u8 reg_start_addr; + u8 msb, lsb; + u8 page; + u32 mask; + + + u8 reading[4]; + u8 writing[4]; + u32 reading_tmp; + u32 writing_tmp; + + + reg_start_addr = registers[reg].start_address; + msb = registers[reg].msb; + lsb = registers[reg].lsb; + page = registers[reg].page; + + len = (msb >> 3) + 1; + mask = REG_MASK(msb - lsb); + + + ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len); + if (ret) + goto err; + + reading_tmp = 0; + for (i = 0; i < len; i++) + reading_tmp |= reading[i] << ((len - 1 - i) * 8); + + writing_tmp = reading_tmp & ~(mask << lsb); + writing_tmp |= ((val & mask) << lsb); + + + for (i = 0; i < len; i++) + writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff; + + ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len); + if (ret) + goto err; + + return ret; + +err: + dbg("%s: failed=%d", __func__, ret); + return ret; + +} + + +static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int ret; + struct rtl2832_priv *priv = fe->demodulator_priv; + + dbg("%s: enable=%d", __func__, enable); + + /* gate already open or close */ + if (priv->i2c_gate_state == enable) + return 0; + + ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable ? 0x1 : 0x0)); + if (ret) + goto err; + + priv->i2c_gate_state = enable; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + + + +static int rtl2832_init(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + int i, ret; + + u8 en_bbin; + u64 pset_iffreq; + + /* initialization values for the demodulator registers */ + struct rtl2832_reg_value rtl2832_initial_regs[] = { + {DVBT_AD_EN_REG, 0x1}, + {DVBT_AD_EN_REG1, 0x1}, + {DVBT_RSD_BER_FAIL_VAL, 0x2800}, + {DVBT_MGD_THD0, 0x10}, + {DVBT_MGD_THD1, 0x20}, + {DVBT_MGD_THD2, 0x20}, + {DVBT_MGD_THD3, 0x40}, + {DVBT_MGD_THD4, 0x22}, + {DVBT_MGD_THD5, 0x32}, + {DVBT_MGD_THD6, 0x37}, + {DVBT_MGD_THD7, 0x39}, + {DVBT_EN_BK_TRK, 0x0}, + {DVBT_EN_CACQ_NOTCH, 0x0}, + {DVBT_AD_AV_REF, 0x2a}, + {DVBT_REG_PI, 0x6}, + {DVBT_PIP_ON, 0x0}, + {DVBT_CDIV_PH0, 0x8}, + {DVBT_CDIV_PH1, 0x8}, + {DVBT_SCALE1_B92, 0x4}, + {DVBT_SCALE1_B93, 0xb0}, + {DVBT_SCALE1_BA7, 0x78}, + {DVBT_SCALE1_BA9, 0x28}, + {DVBT_SCALE1_BAA, 0x59}, + {DVBT_SCALE1_BAB, 0x83}, + {DVBT_SCALE1_BAC, 0xd4}, + {DVBT_SCALE1_BB0, 0x65}, + {DVBT_SCALE1_BB1, 0x43}, + {DVBT_KB_P1, 0x1}, + {DVBT_KB_P2, 0x4}, + {DVBT_KB_P3, 0x7}, + {DVBT_K1_CR_STEP12, 0xa}, + {DVBT_REG_GPE, 0x1}, + {DVBT_SERIAL, 0x0}, + {DVBT_CDIV_PH0, 0x9}, + {DVBT_CDIV_PH1, 0x9}, + {DVBT_MPEG_IO_OPT_2_2, 0x0}, + {DVBT_MPEG_IO_OPT_1_0, 0x0}, + {DVBT_TRK_KS_P2, 0x4}, + {DVBT_TRK_KS_I2, 0x7}, + {DVBT_TR_THD_SET2, 0x6}, + {DVBT_TRK_KC_I2, 0x5}, + {DVBT_CR_THD_SET2, 0x1}, + {DVBT_SPEC_INV, 0x0}, + {DVBT_DAGC_TRG_VAL, 0x5a}, + {DVBT_AGC_TARG_VAL_0, 0x0}, + {DVBT_AGC_TARG_VAL_8_1, 0x5a}, + {DVBT_AAGC_LOOP_GAIN, 0x16}, + {DVBT_LOOP_GAIN2_3_0, 0x6}, + {DVBT_LOOP_GAIN2_4, 0x1}, + {DVBT_LOOP_GAIN3, 0x16}, + {DVBT_VTOP1, 0x35}, + {DVBT_VTOP2, 0x21}, + {DVBT_VTOP3, 0x21}, + {DVBT_KRF1, 0x0}, + {DVBT_KRF2, 0x40}, + {DVBT_KRF3, 0x10}, + {DVBT_KRF4, 0x10}, + {DVBT_IF_AGC_MIN, 0x80}, + {DVBT_IF_AGC_MAX, 0x7f}, + {DVBT_RF_AGC_MIN, 0x80}, + {DVBT_RF_AGC_MAX, 0x7f}, + {DVBT_POLAR_RF_AGC, 0x0}, + {DVBT_POLAR_IF_AGC, 0x0}, + {DVBT_AD7_SETTING, 0xe9bf}, + {DVBT_EN_GI_PGA, 0x0}, + {DVBT_THD_LOCK_UP, 0x0}, + {DVBT_THD_LOCK_DW, 0x0}, + {DVBT_THD_UP1, 0x11}, + {DVBT_THD_DW1, 0xef}, + {DVBT_INTER_CNT_LEN, 0xc}, + {DVBT_GI_PGA_STATE, 0x0}, + {DVBT_EN_AGC_PGA, 0x1}, + {DVBT_IF_AGC_MAN, 0x0}, + }; + + + dbg("%s", __func__); + + en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0); + + /* + * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) + * / CrystalFreqHz) + */ + pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal; + pset_iffreq *= 0x400000; + pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); + pset_iffreq = pset_iffreq & 0x3fffff; + + + + for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) { + ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg, + rtl2832_initial_regs[i].value); + if (ret) + goto err; + } + + /* if frequency settings */ + ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); + if (ret) + goto err; + + ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); + if (ret) + goto err; + + priv->sleeping = false; + + return ret; + +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int rtl2832_sleep(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + + dbg("%s", __func__); + priv->sleeping = true; + return 0; +} + +int rtl2832_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *s) +{ + dbg("%s", __func__); + s->min_delay_ms = 1000; + s->step_size = fe->ops.info.frequency_stepsize * 2; + s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; + return 0; +} + +static int rtl2832_set_frontend(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i, j; + u64 bw_mode, num, num2; + u32 resamp_ratio, cfreq_off_ratio; + + + static u8 bw_params[3][32] = { + /* 6 MHz bandwidth */ + { + 0xf5, 0xff, 0x15, 0x38, 0x5d, 0x6d, 0x52, 0x07, 0xfa, 0x2f, + 0x53, 0xf5, 0x3f, 0xca, 0x0b, 0x91, 0xea, 0x30, 0x63, 0xb2, + 0x13, 0xda, 0x0b, 0xc4, 0x18, 0x7e, 0x16, 0x66, 0x08, 0x67, + 0x19, 0xe0, + }, + + /* 7 MHz bandwidth */ + { + 0xe7, 0xcc, 0xb5, 0xba, 0xe8, 0x2f, 0x67, 0x61, 0x00, 0xaf, + 0x86, 0xf2, 0xbf, 0x59, 0x04, 0x11, 0xb6, 0x33, 0xa4, 0x30, + 0x15, 0x10, 0x0a, 0x42, 0x18, 0xf8, 0x17, 0xd9, 0x07, 0x22, + 0x19, 0x10, + }, + + /* 8 MHz bandwidth */ + { + 0x09, 0xf6, 0xd2, 0xa7, 0x9a, 0xc9, 0x27, 0x77, 0x06, 0xbf, + 0xec, 0xf4, 0x4f, 0x0b, 0xfc, 0x01, 0x63, 0x35, 0x54, 0xa7, + 0x16, 0x66, 0x08, 0xb4, 0x19, 0x6e, 0x19, 0x65, 0x05, 0xc8, + 0x19, 0xe0, + }, + }; + + + dbg("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__, + c->frequency, c->bandwidth_hz, c->inversion); + + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + + + switch (c->bandwidth_hz) { + case 6000000: + i = 0; + bw_mode = 48000000; + break; + case 7000000: + i = 1; + bw_mode = 56000000; + break; + case 8000000: + i = 2; + bw_mode = 64000000; + break; + default: + dbg("invalid bandwidth"); + return -EINVAL; + } + + for (j = 0; j < sizeof(bw_params[0]); j++) { + ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1); + if (ret) + goto err; + } + + /* calculate and set resample ratio + * RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) + * / ConstWithBandwidthMode) + */ + num = priv->cfg.xtal * 7; + num *= 0x400000; + num = div_u64(num, bw_mode); + resamp_ratio = num & 0x3ffffff; + ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio); + if (ret) + goto err; + + /* calculate and set cfreq off ratio + * CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20) + * / (CrystalFreqHz * 7)) + */ + num = bw_mode << 20; + num2 = priv->cfg.xtal * 7; + num = div_u64(num, num2); + num = -num; + cfreq_off_ratio = num & 0xfffff; + ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio); + if (ret) + goto err; + + + /* soft reset */ + ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1); + if (ret) + goto err; + + ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0); + if (ret) + goto err; + + return ret; +err: + info("%s: failed=%d", __func__, ret); + return ret; +} + +static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + int ret; + u32 tmp; + *status = 0; + + + dbg("%s", __func__); + if (priv->sleeping) + return 0; + + ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp); + if (ret) + goto err; + + if (tmp == 11) { + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } + /* TODO find out if this is also true for rtl2832? */ + /*else if (tmp == 10) { + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + }*/ + + return ret; +err: + info("%s: failed=%d", __func__, ret); + return ret; +} + +static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + *snr = 0; + return 0; +} + +static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + return 0; +} + +static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + return 0; +} + + +static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + *strength = 0; + return 0; +} + +static struct dvb_frontend_ops rtl2832_ops; + +static void rtl2832_release(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; + + dbg("%s", __func__); + kfree(priv); +} + +struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg, + struct i2c_adapter *i2c) +{ + struct rtl2832_priv *priv = NULL; + int ret = 0; + u8 tmp; + + dbg("%s", __func__); + + /* allocate memory for the internal state */ + priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL); + if (priv == NULL) + goto err; + + /* setup the priv */ + priv->i2c = i2c; + priv->tuner = cfg->tuner; + memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config)); + + /* check if the demod is there */ + ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp); + if (ret) + goto err; + + /* create dvb_frontend */ + memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops)); + priv->fe.demodulator_priv = priv; + + /* TODO implement sleep mode */ + priv->sleeping = true; + + return &priv->fe; +err: + dbg("%s: failed=%d", __func__, ret); + kfree(priv); + return NULL; +} +EXPORT_SYMBOL(rtl2832_attach); + +static struct dvb_frontend_ops rtl2832_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Realtek RTL2832 (DVB-T)", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + + .release = rtl2832_release, + + .init = rtl2832_init, + .sleep = rtl2832_sleep, + + .get_tune_settings = rtl2832_get_tune_settings, + + .set_frontend = rtl2832_set_frontend, + + .read_status = rtl2832_read_status, + .read_snr = rtl2832_read_snr, + .read_ber = rtl2832_read_ber, + .read_ucblocks = rtl2832_read_ucblocks, + .read_signal_strength = rtl2832_read_signal_strength, + .i2c_gate_ctrl = rtl2832_i2c_gate_ctrl, +}; + +MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>"); +MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.5"); diff --git a/drivers/media/dvb/frontends/rtl2832.h b/drivers/media/dvb/frontends/rtl2832.h new file mode 100644 index 000000000000..d94dc9a3fa62 --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2832.h @@ -0,0 +1,74 @@ +/* + * Realtek RTL2832 DVB-T demodulator driver + * + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef RTL2832_H +#define RTL2832_H + +#include <linux/dvb/frontend.h> + +struct rtl2832_config { + /* + * Demodulator I2C address. + */ + u8 i2c_addr; + + /* + * Xtal frequency. + * Hz + * 4000000, 16000000, 25000000, 28800000 + */ + u32 xtal; + + /* + * IFs for all used modes. + * Hz + * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000 + */ + u32 if_dvbt; + + /* + */ + u8 tuner; +}; + + +#if defined(CONFIG_DVB_RTL2832) || \ + (defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE)) +extern struct dvb_frontend *rtl2832_attach( + const struct rtl2832_config *cfg, + struct i2c_adapter *i2c +); + +extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter( + struct dvb_frontend *fe +); +#else +static inline struct dvb_frontend *rtl2832_attach( + const struct rtl2832_config *config, + struct i2c_adapter *i2c +) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + + +#endif /* RTL2832_H */ diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h b/drivers/media/dvb/frontends/rtl2832_priv.h new file mode 100644 index 000000000000..0ce9502da8ba --- /dev/null +++ b/drivers/media/dvb/frontends/rtl2832_priv.h @@ -0,0 +1,260 @@ +/* + * Realtek RTL2832 DVB-T demodulator driver + * + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef RTL2832_PRIV_H +#define RTL2832_PRIV_H + +#include "dvb_frontend.h" +#include "rtl2832.h" + +#define LOG_PREFIX "rtl2832" + +#undef dbg +#define dbg(f, arg...) \ +do { \ + if (rtl2832_debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg); \ +} while (0) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +struct rtl2832_priv { + struct i2c_adapter *i2c; + struct dvb_frontend fe; + struct rtl2832_config cfg; + + bool i2c_gate_state; + bool sleeping; + + u8 tuner; + u8 page; /* active register page */ +}; + +struct rtl2832_reg_entry { + u8 page; + u8 start_address; + u8 msb; + u8 lsb; +}; + +struct rtl2832_reg_value { + int reg; + u32 value; +}; + + +/* Demod register bit names */ +enum DVBT_REG_BIT_NAME { + DVBT_SOFT_RST, + DVBT_IIC_REPEAT, + DVBT_TR_WAIT_MIN_8K, + DVBT_RSD_BER_FAIL_VAL, + DVBT_EN_BK_TRK, + DVBT_REG_PI, + DVBT_REG_PFREQ_1_0, + DVBT_PD_DA8, + DVBT_LOCK_TH, + DVBT_BER_PASS_SCAL, + DVBT_CE_FFSM_BYPASS, + DVBT_ALPHAIIR_N, + DVBT_ALPHAIIR_DIF, + DVBT_EN_TRK_SPAN, + DVBT_LOCK_TH_LEN, + DVBT_CCI_THRE, + DVBT_CCI_MON_SCAL, + DVBT_CCI_M0, + DVBT_CCI_M1, + DVBT_CCI_M2, + DVBT_CCI_M3, + DVBT_SPEC_INIT_0, + DVBT_SPEC_INIT_1, + DVBT_SPEC_INIT_2, + DVBT_AD_EN_REG, + DVBT_AD_EN_REG1, + DVBT_EN_BBIN, + DVBT_MGD_THD0, + DVBT_MGD_THD1, + DVBT_MGD_THD2, + DVBT_MGD_THD3, + DVBT_MGD_THD4, + DVBT_MGD_THD5, + DVBT_MGD_THD6, + DVBT_MGD_THD7, + DVBT_EN_CACQ_NOTCH, + DVBT_AD_AV_REF, + DVBT_PIP_ON, + DVBT_SCALE1_B92, + DVBT_SCALE1_B93, + DVBT_SCALE1_BA7, + DVBT_SCALE1_BA9, + DVBT_SCALE1_BAA, + DVBT_SCALE1_BAB, + DVBT_SCALE1_BAC, + DVBT_SCALE1_BB0, + DVBT_SCALE1_BB1, + DVBT_KB_P1, + DVBT_KB_P2, + DVBT_KB_P3, + DVBT_OPT_ADC_IQ, + DVBT_AD_AVI, + DVBT_AD_AVQ, + DVBT_K1_CR_STEP12, + DVBT_TRK_KS_P2, + DVBT_TRK_KS_I2, + DVBT_TR_THD_SET2, + DVBT_TRK_KC_P2, + DVBT_TRK_KC_I2, + DVBT_CR_THD_SET2, + DVBT_PSET_IFFREQ, + DVBT_SPEC_INV, + DVBT_BW_INDEX, + DVBT_RSAMP_RATIO, + DVBT_CFREQ_OFF_RATIO, + DVBT_FSM_STAGE, + DVBT_RX_CONSTEL, + DVBT_RX_HIER, + DVBT_RX_C_RATE_LP, + DVBT_RX_C_RATE_HP, + DVBT_GI_IDX, + DVBT_FFT_MODE_IDX, + DVBT_RSD_BER_EST, + DVBT_CE_EST_EVM, + DVBT_RF_AGC_VAL, + DVBT_IF_AGC_VAL, + DVBT_DAGC_VAL, + DVBT_SFREQ_OFF, + DVBT_CFREQ_OFF, + DVBT_POLAR_RF_AGC, + DVBT_POLAR_IF_AGC, + DVBT_AAGC_HOLD, + DVBT_EN_RF_AGC, + DVBT_EN_IF_AGC, + DVBT_IF_AGC_MIN, + DVBT_IF_AGC_MAX, + DVBT_RF_AGC_MIN, + DVBT_RF_AGC_MAX, + DVBT_IF_AGC_MAN, + DVBT_IF_AGC_MAN_VAL, + DVBT_RF_AGC_MAN, + DVBT_RF_AGC_MAN_VAL, + DVBT_DAGC_TRG_VAL, + DVBT_AGC_TARG_VAL, + DVBT_LOOP_GAIN_3_0, + DVBT_LOOP_GAIN_4, + DVBT_VTOP, + DVBT_KRF, + DVBT_AGC_TARG_VAL_0, + DVBT_AGC_TARG_VAL_8_1, + DVBT_AAGC_LOOP_GAIN, + DVBT_LOOP_GAIN2_3_0, + DVBT_LOOP_GAIN2_4, + DVBT_LOOP_GAIN3, + DVBT_VTOP1, + DVBT_VTOP2, + DVBT_VTOP3, + DVBT_KRF1, + DVBT_KRF2, + DVBT_KRF3, + DVBT_KRF4, + DVBT_EN_GI_PGA, + DVBT_THD_LOCK_UP, + DVBT_THD_LOCK_DW, + DVBT_THD_UP1, + DVBT_THD_DW1, + DVBT_INTER_CNT_LEN, + DVBT_GI_PGA_STATE, + DVBT_EN_AGC_PGA, + DVBT_CKOUTPAR, + DVBT_CKOUT_PWR, + DVBT_SYNC_DUR, + DVBT_ERR_DUR, + DVBT_SYNC_LVL, + DVBT_ERR_LVL, + DVBT_VAL_LVL, + DVBT_SERIAL, + DVBT_SER_LSB, + DVBT_CDIV_PH0, + DVBT_CDIV_PH1, + DVBT_MPEG_IO_OPT_2_2, + DVBT_MPEG_IO_OPT_1_0, + DVBT_CKOUTPAR_PIP, + DVBT_CKOUT_PWR_PIP, + DVBT_SYNC_LVL_PIP, + DVBT_ERR_LVL_PIP, + DVBT_VAL_LVL_PIP, + DVBT_CKOUTPAR_PID, + DVBT_CKOUT_PWR_PID, + DVBT_SYNC_LVL_PID, + DVBT_ERR_LVL_PID, + DVBT_VAL_LVL_PID, + DVBT_SM_PASS, + DVBT_UPDATE_REG_2, + DVBT_BTHD_P3, + DVBT_BTHD_D3, + DVBT_FUNC4_REG0, + DVBT_FUNC4_REG1, + DVBT_FUNC4_REG2, + DVBT_FUNC4_REG3, + DVBT_FUNC4_REG4, + DVBT_FUNC4_REG5, + DVBT_FUNC4_REG6, + DVBT_FUNC4_REG7, + DVBT_FUNC4_REG8, + DVBT_FUNC4_REG9, + DVBT_FUNC4_REG10, + DVBT_FUNC5_REG0, + DVBT_FUNC5_REG1, + DVBT_FUNC5_REG2, + DVBT_FUNC5_REG3, + DVBT_FUNC5_REG4, + DVBT_FUNC5_REG5, + DVBT_FUNC5_REG6, + DVBT_FUNC5_REG7, + DVBT_FUNC5_REG8, + DVBT_FUNC5_REG9, + DVBT_FUNC5_REG10, + DVBT_FUNC5_REG11, + DVBT_FUNC5_REG12, + DVBT_FUNC5_REG13, + DVBT_FUNC5_REG14, + DVBT_FUNC5_REG15, + DVBT_FUNC5_REG16, + DVBT_FUNC5_REG17, + DVBT_FUNC5_REG18, + DVBT_AD7_SETTING, + DVBT_RSSI_R, + DVBT_ACI_DET_IND, + DVBT_REG_MON, + DVBT_REG_MONSEL, + DVBT_REG_GPE, + DVBT_REG_GPO, + DVBT_REG_4MSEL, + DVBT_TEST_REG_1, + DVBT_TEST_REG_2, + DVBT_TEST_REG_3, + DVBT_TEST_REG_4, + DVBT_REG_BIT_NAME_ITEM_TERMINATOR, +}; + +#endif /* RTL2832_PRIV_H */ diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 2322257c69ae..e2fec9ebf947 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -634,7 +634,6 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe) struct s5h1420_state* state = fe->demodulator_priv; int frequency_delta; struct dvb_frontend_tune_settings fesettings; - uint8_t clock_setting; dprintk("enter %s\n", __func__); @@ -679,25 +678,6 @@ static int s5h1420_set_frontend(struct dvb_frontend *fe) else state->fclk = 44000000; - /* Clock */ - switch (state->fclk) { - default: - case 88000000: - clock_setting = 80; - break; - case 86000000: - clock_setting = 78; - break; - case 80000000: - clock_setting = 72; - break; - case 59000000: - clock_setting = 51; - break; - case 44000000: - clock_setting = 36; - break; - } dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8); s5h1420_writereg(state, PLL02, 0x40); diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index 8b0dc74a3298..5d7f8a9b451b 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -1129,7 +1129,6 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber) struct stb0899_internal *internal = &state->internal; u8 lsb, msb; - u32 i; *ber = 0; @@ -1137,14 +1136,9 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber) case SYS_DVBS: case SYS_DSS: if (internal->lock) { - /* average 5 BER values */ - for (i = 0; i < 5; i++) { - msleep(100); - lsb = stb0899_read_reg(state, STB0899_ECNT1L); - msb = stb0899_read_reg(state, STB0899_ECNT1M); - *ber += MAKEWORD16(msb, lsb); - } - *ber /= 5; + lsb = stb0899_read_reg(state, STB0899_ECNT1L); + msb = stb0899_read_reg(state, STB0899_ECNT1M); + *ber = MAKEWORD16(msb, lsb); /* Viterbi Check */ if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) { /* Error Rate */ @@ -1157,13 +1151,9 @@ static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber) break; case SYS_DVBS2: if (internal->lock) { - /* Average 5 PER values */ - for (i = 0; i < 5; i++) { - msleep(100); - lsb = stb0899_read_reg(state, STB0899_ECNT1L); - msb = stb0899_read_reg(state, STB0899_ECNT1M); - *ber += MAKEWORD16(msb, lsb); - } + lsb = stb0899_read_reg(state, STB0899_ECNT1L); + msb = stb0899_read_reg(state, STB0899_ECNT1M); + *ber = MAKEWORD16(msb, lsb); /* ber = ber * 10 ^ 7 */ *ber *= 10000000; *ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl)))); diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index fdd20c7737b5..2a8aaeb1112d 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -1584,7 +1584,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe) struct stv0367ter_state *ter_state = state->ter_state; int offset = 0, tempo = 0; u8 u_var; - u8 /*constell,*/ counter, tps_rcvd[2]; + u8 /*constell,*/ counter; s8 step; s32 timing_offset = 0; u32 trl_nomrate = 0, InternalFreq = 0, temp = 0; @@ -1709,9 +1709,6 @@ static int stv0367ter_algo(struct dvb_frontend *fe) return 0; ter_state->state = FE_TER_LOCKOK; - /* update results */ - tps_rcvd[0] = stv0367_readreg(state, R367TER_TPS_RCVD2); - tps_rcvd[1] = stv0367_readreg(state, R367TER_TPS_RCVD3); ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE); ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD); diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index d79e69f65cbb..ea86a5603e57 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -3172,7 +3172,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) enum stv090x_signal_state signal_state = STV090x_NOCARRIER; u32 reg; s32 agc1_power, power_iq = 0, i; - int lock = 0, low_sr = 0, no_signal = 0; + int lock = 0, low_sr = 0; reg = STV090x_READ_DEMOD(state, TSCFGH); STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */ @@ -3413,7 +3413,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) goto err; } else { signal_state = STV090x_NODATA; - no_signal = stv090x_chk_signal(state); + stv090x_chk_signal(state); } } return signal_state; diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c index c21bc92d2811..703c3d05f9f4 100644 --- a/drivers/media/dvb/frontends/tda10071.c +++ b/drivers/media/dvb/frontends/tda10071.c @@ -20,10 +20,6 @@ #include "tda10071_priv.h" -int tda10071_debug; -module_param_named(debug, tda10071_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - static struct dvb_frontend_ops tda10071_ops; /* write multiple registers */ @@ -48,7 +44,8 @@ static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val, if (ret == 1) { ret = 0; } else { - warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); + dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ + "len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -79,7 +76,8 @@ static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val, memcpy(val, buf, len); ret = 0; } else { - warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); + dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ + "len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } return ret; @@ -170,7 +168,7 @@ static int tda10071_cmd_execute(struct tda10071_priv *priv, usleep_range(200, 5000); } - dbg("%s: loop=%d", __func__, i); + dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); if (i == 0) { ret = -ETIMEDOUT; @@ -179,7 +177,7 @@ static int tda10071_cmd_execute(struct tda10071_priv *priv, return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -196,7 +194,8 @@ static int tda10071_set_tone(struct dvb_frontend *fe, goto error; } - dbg("%s: tone_mode=%d", __func__, fe_sec_tone_mode); + dev_dbg(&priv->i2c->dev, "%s: tone_mode=%d\n", __func__, + fe_sec_tone_mode); switch (fe_sec_tone_mode) { case SEC_TONE_ON: @@ -206,24 +205,25 @@ static int tda10071_set_tone(struct dvb_frontend *fe, tone = 0; break; default: - dbg("%s: invalid fe_sec_tone_mode", __func__); + dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_tone_mode\n", + __func__); ret = -EINVAL; goto error; } - cmd.args[0x00] = CMD_LNB_PCB_CONFIG; - cmd.args[0x01] = 0; - cmd.args[0x02] = 0x00; - cmd.args[0x03] = 0x00; - cmd.args[0x04] = tone; - cmd.len = 0x05; + cmd.args[0] = CMD_LNB_PCB_CONFIG; + cmd.args[1] = 0; + cmd.args[2] = 0x00; + cmd.args[3] = 0x00; + cmd.args[4] = tone; + cmd.len = 5; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -240,7 +240,7 @@ static int tda10071_set_voltage(struct dvb_frontend *fe, goto error; } - dbg("%s: voltage=%d", __func__, fe_sec_voltage); + dev_dbg(&priv->i2c->dev, "%s: voltage=%d\n", __func__, fe_sec_voltage); switch (fe_sec_voltage) { case SEC_VOLTAGE_13: @@ -253,22 +253,23 @@ static int tda10071_set_voltage(struct dvb_frontend *fe, voltage = 0; break; default: - dbg("%s: invalid fe_sec_voltage", __func__); + dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n", + __func__); ret = -EINVAL; goto error; }; - cmd.args[0x00] = CMD_LNB_SET_DC_LEVEL; - cmd.args[0x01] = 0; - cmd.args[0x02] = voltage; - cmd.len = 0x03; + cmd.args[0] = CMD_LNB_SET_DC_LEVEL; + cmd.args[1] = 0; + cmd.args[2] = voltage; + cmd.len = 3; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -285,9 +286,10 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe, goto error; } - dbg("%s: msg_len=%d", __func__, diseqc_cmd->msg_len); + dev_dbg(&priv->i2c->dev, "%s: msg_len=%d\n", __func__, + diseqc_cmd->msg_len); - if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 16) { + if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) { ret = -EINVAL; goto error; } @@ -301,7 +303,7 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe, usleep_range(10000, 20000); } - dbg("%s: loop=%d", __func__, i); + dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); if (i == 0) { ret = -ETIMEDOUT; @@ -312,22 +314,22 @@ static int tda10071_diseqc_send_master_cmd(struct dvb_frontend *fe, if (ret) goto error; - cmd.args[0x00] = CMD_LNB_SEND_DISEQC; - cmd.args[0x01] = 0; - cmd.args[0x02] = 0; - cmd.args[0x03] = 0; - cmd.args[0x04] = 2; - cmd.args[0x05] = 0; - cmd.args[0x06] = diseqc_cmd->msg_len; - memcpy(&cmd.args[0x07], diseqc_cmd->msg, diseqc_cmd->msg_len); - cmd.len = 0x07 + diseqc_cmd->msg_len; + cmd.args[0] = CMD_LNB_SEND_DISEQC; + cmd.args[1] = 0; + cmd.args[2] = 0; + cmd.args[3] = 0; + cmd.args[4] = 2; + cmd.args[5] = 0; + cmd.args[6] = diseqc_cmd->msg_len; + memcpy(&cmd.args[7], diseqc_cmd->msg, diseqc_cmd->msg_len); + cmd.len = 7 + diseqc_cmd->msg_len; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -344,7 +346,7 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe, goto error; } - dbg("%s:", __func__); + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); /* wait LNB RX */ for (i = 500, tmp = 0; i && !tmp; i--) { @@ -355,7 +357,7 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe, usleep_range(10000, 20000); } - dbg("%s: loop=%d", __func__, i); + dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); if (i == 0) { ret = -ETIMEDOUT; @@ -372,9 +374,9 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe, reply->msg_len = sizeof(reply->msg); /* truncate API max */ /* read reply */ - cmd.args[0x00] = CMD_LNB_UPDATE_REPLY; - cmd.args[0x01] = 0; - cmd.len = 0x02; + cmd.args[0] = CMD_LNB_UPDATE_REPLY; + cmd.args[1] = 0; + cmd.len = 2; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -385,7 +387,7 @@ static int tda10071_diseqc_recv_slave_reply(struct dvb_frontend *fe, return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -402,7 +404,8 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe, goto error; } - dbg("%s: fe_sec_mini_cmd=%d", __func__, fe_sec_mini_cmd); + dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__, + fe_sec_mini_cmd); switch (fe_sec_mini_cmd) { case SEC_MINI_A: @@ -412,7 +415,8 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe, burst = 1; break; default: - dbg("%s: invalid fe_sec_mini_cmd", __func__); + dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_mini_cmd\n", + __func__); ret = -EINVAL; goto error; } @@ -426,7 +430,7 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe, usleep_range(10000, 20000); } - dbg("%s: loop=%d", __func__, i); + dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i); if (i == 0) { ret = -ETIMEDOUT; @@ -437,17 +441,17 @@ static int tda10071_diseqc_send_burst(struct dvb_frontend *fe, if (ret) goto error; - cmd.args[0x00] = CMD_LNB_SEND_TONEBURST; - cmd.args[0x01] = 0; - cmd.args[0x02] = burst; - cmd.len = 0x03; + cmd.args[0] = CMD_LNB_SEND_TONEBURST; + cmd.args[1] = 0; + cmd.args[2] = burst; + cmd.len = 3; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -481,7 +485,7 @@ static int tda10071_read_status(struct dvb_frontend *fe, fe_status_t *status) return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -506,7 +510,7 @@ static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr) return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -523,9 +527,9 @@ static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength) goto error; } - cmd.args[0x00] = CMD_GET_AGCACC; - cmd.args[0x01] = 0; - cmd.len = 0x02; + cmd.args[0] = CMD_GET_AGCACC; + cmd.args[1] = 0; + cmd.len = 2; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -545,7 +549,7 @@ static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -583,17 +587,18 @@ static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber) goto error; if (priv->meas_count[i] == tmp) { - dbg("%s: meas not ready=%02x", __func__, tmp); + dev_dbg(&priv->i2c->dev, "%s: meas not ready=%02x\n", __func__, + tmp); *ber = priv->ber; return 0; } else { priv->meas_count[i] = tmp; } - cmd.args[0x00] = CMD_BER_UPDATE_COUNTERS; - cmd.args[0x01] = 0; - cmd.args[0x02] = i; - cmd.len = 0x03; + cmd.args[0] = CMD_BER_UPDATE_COUNTERS; + cmd.args[1] = 0; + cmd.args[2] = i; + cmd.len = 3; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -612,7 +617,7 @@ static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber) return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -632,7 +637,7 @@ static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -644,10 +649,11 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) int ret, i; u8 mode, rolloff, pilot, inversion, div; - dbg("%s: delivery_system=%d modulation=%d frequency=%d " \ - "symbol_rate=%d inversion=%d pilot=%d rolloff=%d", __func__, - c->delivery_system, c->modulation, c->frequency, - c->symbol_rate, c->inversion, c->pilot, c->rolloff); + dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d " \ + "frequency=%d symbol_rate=%d inversion=%d pilot=%d " \ + "rolloff=%d\n", __func__, c->delivery_system, c->modulation, + c->frequency, c->symbol_rate, c->inversion, c->pilot, + c->rolloff); priv->delivery_system = SYS_UNDEFINED; @@ -669,7 +675,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) inversion = 3; break; default: - dbg("%s: invalid inversion", __func__); + dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n", __func__); ret = -EINVAL; goto error; } @@ -692,7 +698,8 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) break; case ROLLOFF_AUTO: default: - dbg("%s: invalid rolloff", __func__); + dev_dbg(&priv->i2c->dev, "%s: invalid rolloff\n", + __func__); ret = -EINVAL; goto error; } @@ -708,13 +715,15 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) pilot = 2; break; default: - dbg("%s: invalid pilot", __func__); + dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n", + __func__); ret = -EINVAL; goto error; } break; default: - dbg("%s: invalid delivery_system", __func__); + dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n", + __func__); ret = -EINVAL; goto error; } @@ -724,13 +733,15 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) c->modulation == TDA10071_MODCOD[i].modulation && c->fec_inner == TDA10071_MODCOD[i].fec) { mode = TDA10071_MODCOD[i].val; - dbg("%s: mode found=%02x", __func__, mode); + dev_dbg(&priv->i2c->dev, "%s: mode found=%02x\n", + __func__, mode); break; } } if (mode == 0xff) { - dbg("%s: invalid parameter combination", __func__); + dev_dbg(&priv->i2c->dev, "%s: invalid parameter combination\n", + __func__); ret = -EINVAL; goto error; } @@ -748,22 +759,22 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) if (ret) goto error; - cmd.args[0x00] = CMD_CHANGE_CHANNEL; - cmd.args[0x01] = 0; - cmd.args[0x02] = mode; - cmd.args[0x03] = (c->frequency >> 16) & 0xff; - cmd.args[0x04] = (c->frequency >> 8) & 0xff; - cmd.args[0x05] = (c->frequency >> 0) & 0xff; - cmd.args[0x06] = ((c->symbol_rate / 1000) >> 8) & 0xff; - cmd.args[0x07] = ((c->symbol_rate / 1000) >> 0) & 0xff; - cmd.args[0x08] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff; - cmd.args[0x09] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff; - cmd.args[0x0a] = rolloff; - cmd.args[0x0b] = inversion; - cmd.args[0x0c] = pilot; - cmd.args[0x0d] = 0x00; - cmd.args[0x0e] = 0x00; - cmd.len = 0x0f; + cmd.args[0] = CMD_CHANGE_CHANNEL; + cmd.args[1] = 0; + cmd.args[2] = mode; + cmd.args[3] = (c->frequency >> 16) & 0xff; + cmd.args[4] = (c->frequency >> 8) & 0xff; + cmd.args[5] = (c->frequency >> 0) & 0xff; + cmd.args[6] = ((c->symbol_rate / 1000) >> 8) & 0xff; + cmd.args[7] = ((c->symbol_rate / 1000) >> 0) & 0xff; + cmd.args[8] = (tda10071_ops.info.frequency_tolerance >> 8) & 0xff; + cmd.args[9] = (tda10071_ops.info.frequency_tolerance >> 0) & 0xff; + cmd.args[10] = rolloff; + cmd.args[11] = inversion; + cmd.args[12] = pilot; + cmd.args[13] = 0x00; + cmd.args[14] = 0x00; + cmd.len = 15; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -772,7 +783,7 @@ static int tda10071_set_frontend(struct dvb_frontend *fe) return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -829,7 +840,7 @@ static int tda10071_get_frontend(struct dvb_frontend *fe) return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -915,10 +926,10 @@ static int tda10071_init(struct dvb_frontend *fe) goto error; } - cmd.args[0x00] = CMD_SET_SLEEP_MODE; - cmd.args[0x01] = 0; - cmd.args[0x02] = 0; - cmd.len = 0x03; + cmd.args[0] = CMD_SET_SLEEP_MODE; + cmd.args[1] = 0; + cmd.args[2] = 0; + cmd.len = 3; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -929,10 +940,11 @@ static int tda10071_init(struct dvb_frontend *fe) /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent); if (ret) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more" \ - " details on firmware-problems. (%d)", - fw_file, ret); + dev_err(&priv->i2c->dev, "%s: did not find the " \ + "firmware file. (%s) Please see " \ + "linux/Documentation/dvb/ for more " \ + "details on firmware-problems. (%d)\n", + KBUILD_MODNAME, fw_file, ret); goto error; } @@ -961,10 +973,11 @@ static int tda10071_init(struct dvb_frontend *fe) if (ret) goto error_release_firmware; - info("found a '%s' in cold state, will try to load a firmware", - tda10071_ops.info.name); - - info("downloading firmware from file '%s'", fw_file); + dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state, " \ + "will try to load a firmware\n", KBUILD_MODNAME, + tda10071_ops.info.name); + dev_info(&priv->i2c->dev, "%s: downloading firmware from " \ + "file '%s'\n", KBUILD_MODNAME, fw_file); /* do not download last byte */ fw_size = fw->size - 1; @@ -978,7 +991,9 @@ static int tda10071_init(struct dvb_frontend *fe) ret = tda10071_wr_regs(priv, 0xfa, (u8 *) &fw->data[fw_size - remaining], len); if (ret) { - err("firmware download failed=%d", ret); + dev_err(&priv->i2c->dev, "%s: firmware " \ + "download failed=%d\n", + KBUILD_MODNAME, ret); if (ret) goto error_release_firmware; } @@ -1002,15 +1017,16 @@ static int tda10071_init(struct dvb_frontend *fe) goto error; if (tmp) { - info("firmware did not run"); + dev_info(&priv->i2c->dev, "%s: firmware did not run\n", + KBUILD_MODNAME); ret = -EFAULT; goto error; } else { priv->warm = 1; } - cmd.args[0x00] = CMD_GET_FW_VERSION; - cmd.len = 0x01; + cmd.args[0] = CMD_GET_FW_VERSION; + cmd.len = 1; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -1019,54 +1035,55 @@ static int tda10071_init(struct dvb_frontend *fe) if (ret) goto error; - info("firmware version %d.%d.%d.%d", - buf[0], buf[1], buf[2], buf[3]); - info("found a '%s' in warm state.", tda10071_ops.info.name); + dev_info(&priv->i2c->dev, "%s: firmware version %d.%d.%d.%d\n", + KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3]); + dev_info(&priv->i2c->dev, "%s: found a '%s' in warm state\n", + KBUILD_MODNAME, tda10071_ops.info.name); ret = tda10071_rd_regs(priv, 0x81, buf, 2); if (ret) goto error; - cmd.args[0x00] = CMD_DEMOD_INIT; - cmd.args[0x01] = ((priv->cfg.xtal / 1000) >> 8) & 0xff; - cmd.args[0x02] = ((priv->cfg.xtal / 1000) >> 0) & 0xff; - cmd.args[0x03] = buf[0]; - cmd.args[0x04] = buf[1]; - cmd.args[0x05] = priv->cfg.pll_multiplier; - cmd.args[0x06] = priv->cfg.spec_inv; - cmd.args[0x07] = 0x00; - cmd.len = 0x08; + cmd.args[0] = CMD_DEMOD_INIT; + cmd.args[1] = ((priv->cfg.xtal / 1000) >> 8) & 0xff; + cmd.args[2] = ((priv->cfg.xtal / 1000) >> 0) & 0xff; + cmd.args[3] = buf[0]; + cmd.args[4] = buf[1]; + cmd.args[5] = priv->cfg.pll_multiplier; + cmd.args[6] = priv->cfg.spec_inv; + cmd.args[7] = 0x00; + cmd.len = 8; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; - cmd.args[0x00] = CMD_TUNER_INIT; - cmd.args[0x01] = 0x00; - cmd.args[0x02] = 0x00; - cmd.args[0x03] = 0x00; - cmd.args[0x04] = 0x00; - cmd.args[0x05] = 0x14; - cmd.args[0x06] = 0x00; - cmd.args[0x07] = 0x03; - cmd.args[0x08] = 0x02; - cmd.args[0x09] = 0x02; - cmd.args[0x0a] = 0x00; - cmd.args[0x0b] = 0x00; - cmd.args[0x0c] = 0x00; - cmd.args[0x0d] = 0x00; - cmd.args[0x0e] = 0x00; - cmd.len = 0x0f; + cmd.args[0] = CMD_TUNER_INIT; + cmd.args[1] = 0x00; + cmd.args[2] = 0x00; + cmd.args[3] = 0x00; + cmd.args[4] = 0x00; + cmd.args[5] = 0x14; + cmd.args[6] = 0x00; + cmd.args[7] = 0x03; + cmd.args[8] = 0x02; + cmd.args[9] = 0x02; + cmd.args[10] = 0x00; + cmd.args[11] = 0x00; + cmd.args[12] = 0x00; + cmd.args[13] = 0x00; + cmd.args[14] = 0x00; + cmd.len = 15; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; - cmd.args[0x00] = CMD_MPEG_CONFIG; - cmd.args[0x01] = 0; - cmd.args[0x02] = priv->cfg.ts_mode; - cmd.args[0x03] = 0x00; - cmd.args[0x04] = 0x04; - cmd.args[0x05] = 0x00; - cmd.len = 0x06; + cmd.args[0] = CMD_MPEG_CONFIG; + cmd.args[1] = 0; + cmd.args[2] = priv->cfg.ts_mode; + cmd.args[3] = 0x00; + cmd.args[4] = 0x04; + cmd.args[5] = 0x00; + cmd.len = 6; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -1075,27 +1092,27 @@ static int tda10071_init(struct dvb_frontend *fe) if (ret) goto error; - cmd.args[0x00] = CMD_LNB_CONFIG; - cmd.args[0x01] = 0; - cmd.args[0x02] = 150; - cmd.args[0x03] = 3; - cmd.args[0x04] = 22; - cmd.args[0x05] = 1; - cmd.args[0x06] = 1; - cmd.args[0x07] = 30; - cmd.args[0x08] = 30; - cmd.args[0x09] = 30; - cmd.args[0x0a] = 30; - cmd.len = 0x0b; + cmd.args[0] = CMD_LNB_CONFIG; + cmd.args[1] = 0; + cmd.args[2] = 150; + cmd.args[3] = 3; + cmd.args[4] = 22; + cmd.args[5] = 1; + cmd.args[6] = 1; + cmd.args[7] = 30; + cmd.args[8] = 30; + cmd.args[9] = 30; + cmd.args[10] = 30; + cmd.len = 11; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; - cmd.args[0x00] = CMD_BER_CONTROL; - cmd.args[0x01] = 0; - cmd.args[0x02] = 14; - cmd.args[0x03] = 14; - cmd.len = 0x04; + cmd.args[0] = CMD_BER_CONTROL; + cmd.args[1] = 0; + cmd.args[2] = 14; + cmd.args[3] = 14; + cmd.len = 4; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -1105,7 +1122,7 @@ static int tda10071_init(struct dvb_frontend *fe) error_release_firmware: release_firmware(fw); error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -1132,10 +1149,10 @@ static int tda10071_sleep(struct dvb_frontend *fe) goto error; } - cmd.args[0x00] = CMD_SET_SLEEP_MODE; - cmd.args[0x01] = 0; - cmd.args[0x02] = 1; - cmd.len = 0x03; + cmd.args[0] = CMD_SET_SLEEP_MODE; + cmd.args[1] = 0; + cmd.args[2] = 1; + cmd.len = 3; ret = tda10071_cmd_execute(priv, &cmd); if (ret) goto error; @@ -1149,7 +1166,7 @@ static int tda10071_sleep(struct dvb_frontend *fe) return ret; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -1208,7 +1225,7 @@ struct dvb_frontend *tda10071_attach(const struct tda10071_config *config, return &priv->fe; error: - dbg("%s: failed=%d", __func__, ret); + dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); kfree(priv); return NULL; } diff --git a/drivers/media/dvb/frontends/tda10071_priv.h b/drivers/media/dvb/frontends/tda10071_priv.h index 93c5e6317f07..0fa85cfa70c2 100644 --- a/drivers/media/dvb/frontends/tda10071_priv.h +++ b/drivers/media/dvb/frontends/tda10071_priv.h @@ -25,19 +25,6 @@ #include "tda10071.h" #include <linux/firmware.h> -#define LOG_PREFIX "tda10071" - -#undef dbg -#define dbg(f, arg...) \ - if (tda10071_debug) \ - printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef err -#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) -#undef info -#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) -#undef warn -#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) - struct tda10071_priv { struct i2c_adapter *i2c; struct dvb_frontend fe; @@ -112,7 +99,7 @@ struct tda10071_reg_val_mask { #define CMD_BER_UPDATE_COUNTERS 0x3f /* firmare command struct */ -#define TDA10071_ARGLEN 0x1e +#define TDA10071_ARGLEN 30 struct tda10071_cmd { u8 args[TDA10071_ARGLEN]; u8 len; diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 7539a5d71029..72ee8de02260 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -217,6 +217,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, memset(&config, 0, sizeof(config)); config.microcode_name = "drxk_a3.mc"; + config.qam_demod_parameter_count = 4; config.adr = 0x29 + (chan->number ^ 2); chan->fe = dvb_attach(drxk_attach, &config, i2c); diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index 7331e8450d1a..9cc55546cc30 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -276,16 +276,13 @@ static void smscore_notify_clients(struct smscore_device_t *coredev) static int smscore_notify_callbacks(struct smscore_device_t *coredev, struct device *device, int arrival) { - struct list_head *next, *first; + struct smscore_device_notifyee_t *elem; int rc = 0; /* note: must be called under g_deviceslock */ - first = &g_smscore_notifyees; - - for (next = first->next; next != first; next = next->next) { - rc = ((struct smscore_device_notifyee_t *) next)-> - hotplug(coredev, device, arrival); + list_for_each_entry(elem, &g_smscore_notifyees, entry) { + rc = elem->hotplug(coredev, device, arrival); if (rc < 0) break; } @@ -940,29 +937,25 @@ static struct smscore_client_t *smscore_find_client(struct smscore_device_t *coredev, int data_type, int id) { - struct smscore_client_t *client = NULL; - struct list_head *next, *first; + struct list_head *first; + struct smscore_client_t *client; unsigned long flags; - struct list_head *firstid, *nextid; - + struct list_head *firstid; + struct smscore_idlist_t *client_id; spin_lock_irqsave(&coredev->clientslock, flags); first = &coredev->clients; - for (next = first->next; - (next != first) && !client; - next = next->next) { - firstid = &((struct smscore_client_t *)next)->idlist; - for (nextid = firstid->next; - nextid != firstid; - nextid = nextid->next) { - if ((((struct smscore_idlist_t *)nextid)->id == id) && - (((struct smscore_idlist_t *)nextid)->data_type == data_type || - (((struct smscore_idlist_t *)nextid)->data_type == 0))) { - client = (struct smscore_client_t *) next; - break; - } + list_for_each_entry(client, first, entry) { + firstid = &client->idlist; + list_for_each_entry(client_id, firstid, entry) { + if ((client_id->id == id) && + (client_id->data_type == data_type || + (client_id->data_type == 0))) + goto found; } } + client = NULL; +found: spin_unlock_irqrestore(&coredev->clientslock, flags); return client; } diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index c257da13d766..8090b87b3066 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -5,6 +5,7 @@ menuconfig RADIO_ADAPTERS bool "Radio Adapters" depends on VIDEO_V4L2 + depends on MEDIA_RADIO_SUPPORT default y ---help--- Say Y here to enable selecting AM/FM radio adapters. @@ -56,6 +57,39 @@ config RADIO_MAXIRADIO To compile this driver as a module, choose M here: the module will be called radio-maxiradio. +config RADIO_SHARK + tristate "Griffin radioSHARK USB radio receiver" + depends on USB && SND + ---help--- + Choose Y here if you have this radio receiver. + + There are 2 versions of this device, this driver is for version 1, + which is white. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-shark. + +config RADIO_SHARK2 + tristate "Griffin radioSHARK2 USB radio receiver" + depends on USB + ---help--- + Choose Y here if you have this radio receiver. + + There are 2 versions of this device, this driver is for version 2, + which is black. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-shark2. config I2C_SI4713 tristate "I2C driver for Silicon Labs Si4713 device" diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index ca8c7d134b95..c03ce4fe74e9 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -11,6 +11,8 @@ obj-$(CONFIG_RADIO_CADET) += radio-cadet.o obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o +obj-$(CONFIG_RADIO_SHARK) += radio-shark.o +obj-$(CONFIG_RADIO_SHARK2) += shark2.o obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o @@ -29,4 +31,6 @@ obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o obj-$(CONFIG_RADIO_WL128X) += wl128x/ +shark2-objs := radio-shark2.o radio-tea5777.o + ccflags-y += -Isound diff --git a/drivers/media/radio/lm7000.h b/drivers/media/radio/lm7000.h new file mode 100644 index 000000000000..139cd6b68824 --- /dev/null +++ b/drivers/media/radio/lm7000.h @@ -0,0 +1,43 @@ +#ifndef __LM7000_H +#define __LM7000_H + +/* Sanyo LM7000 tuner chip control + * + * Copyright 2012 Ondrej Zary <linux@rainbow-software.org> + * based on radio-aimslab.c by M. Kirkwood + * and radio-sf16fmi.c by M. Kirkwood and Petr Vandrovec + */ + +#define LM7000_DATA (1 << 0) +#define LM7000_CLK (1 << 1) +#define LM7000_CE (1 << 2) + +#define LM7000_FM_100 (0 << 20) +#define LM7000_FM_50 (1 << 20) +#define LM7000_FM_25 (2 << 20) +#define LM7000_BIT_FM (1 << 23) + +static inline void lm7000_set_freq(u32 freq, void *handle, + void (*set_pins)(void *handle, u8 pins)) +{ + int i; + u8 data; + u32 val; + + freq += 171200; /* Add 10.7 MHz IF */ + freq /= 400; /* Convert to 25 kHz units */ + val = freq | LM7000_FM_25 | LM7000_BIT_FM; + /* write the 24-bit register, starting with LSB */ + for (i = 0; i < 24; i++) { + data = val & (1 << i) ? LM7000_DATA : 0; + set_pins(handle, data | LM7000_CE); + udelay(2); + set_pins(handle, data | LM7000_CE | LM7000_CLK); + udelay(2); + set_pins(handle, data | LM7000_CE); + udelay(2); + } + set_pins(handle, 0); +} + +#endif /* __LM7000_H */ diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 98e0c8c20312..12c70e876f58 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -37,6 +37,7 @@ #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> #include "radio-isa.h" +#include "lm7000.h" MODULE_AUTHOR("M. Kirkwood"); MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); @@ -72,55 +73,38 @@ static struct radio_isa_card *rtrack_alloc(void) return rt ? &rt->isa : NULL; } -/* The 128+64 on these outb's is to keep the volume stable while tuning. - * Without them, the volume _will_ creep up with each frequency change - * and bit 4 (+16) is to keep the signal strength meter enabled. - */ +#define AIMS_BIT_TUN_CE (1 << 0) +#define AIMS_BIT_TUN_CLK (1 << 1) +#define AIMS_BIT_TUN_DATA (1 << 2) +#define AIMS_BIT_VOL_CE (1 << 3) +#define AIMS_BIT_TUN_STRQ (1 << 4) +/* bit 5 is not connected */ +#define AIMS_BIT_VOL_UP (1 << 6) /* active low */ +#define AIMS_BIT_VOL_DN (1 << 7) /* active low */ -static void send_0_byte(struct radio_isa_card *isa, int on) +void rtrack_set_pins(void *handle, u8 pins) { - outb_p(128+64+16+on+1, isa->io); /* wr-enable + data low */ - outb_p(128+64+16+on+2+1, isa->io); /* clock */ - msleep(1); -} + struct radio_isa_card *isa = handle; + struct rtrack *rt = container_of(isa, struct rtrack, isa); + u8 bits = AIMS_BIT_VOL_DN | AIMS_BIT_VOL_UP | AIMS_BIT_TUN_STRQ; -static void send_1_byte(struct radio_isa_card *isa, int on) -{ - outb_p(128+64+16+on+4+1, isa->io); /* wr-enable+data high */ - outb_p(128+64+16+on+4+2+1, isa->io); /* clock */ - msleep(1); + if (!v4l2_ctrl_g_ctrl(rt->isa.mute)) + bits |= AIMS_BIT_VOL_CE; + + if (pins & LM7000_DATA) + bits |= AIMS_BIT_TUN_DATA; + if (pins & LM7000_CLK) + bits |= AIMS_BIT_TUN_CLK; + if (pins & LM7000_CE) + bits |= AIMS_BIT_TUN_CE; + + outb_p(bits, rt->isa.io); } static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq) { - int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8; - int i; - - freq += 171200; /* Add 10.7 MHz IF */ - freq /= 800; /* Convert to 50 kHz units */ - - send_0_byte(isa, on); /* 0: LSB of frequency */ - - for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ - if (freq & (1 << i)) - send_1_byte(isa, on); - else - send_0_byte(isa, on); - - send_0_byte(isa, on); /* 14: test bit - always 0 */ - send_0_byte(isa, on); /* 15: test bit - always 0 */ - - send_0_byte(isa, on); /* 16: band data 0 - always 0 */ - send_0_byte(isa, on); /* 17: band data 1 - always 0 */ - send_0_byte(isa, on); /* 18: band data 2 - always 0 */ - send_0_byte(isa, on); /* 19: time base - always 0 */ - - send_0_byte(isa, on); /* 20: spacing (0 = 25 kHz) */ - send_1_byte(isa, on); /* 21: spacing (1 = 25 kHz) */ - send_0_byte(isa, on); /* 22: spacing (0 = 25 kHz) */ - send_1_byte(isa, on); /* 23: AM/FM (FM = 1, always) */ + lm7000_set_freq(freq, isa, rtrack_set_pins); - outb(0xd0 + on, isa->io); /* volume steady + sigstr */ return 0; } diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 16a089fad909..697a421c9940 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -41,6 +41,9 @@ #include <linux/io.h> /* outb, outb_p */ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-event.h> MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); @@ -61,14 +64,15 @@ module_param(radio_nr, int, 0); struct cadet { struct v4l2_device v4l2_dev; struct video_device vdev; + struct v4l2_ctrl_handler ctrl_handler; int io; - int users; - int curtuner; + bool is_fm_band; + u32 curfreq; int tunestat; int sigstrength; wait_queue_head_t read_queue; struct timer_list readtimer; - __u8 rdsin, rdsout, rdsstat; + u8 rdsin, rdsout, rdsstat; unsigned char rdsbuf[RDS_BUFFER]; struct mutex lock; int reading; @@ -81,9 +85,9 @@ static struct cadet cadet_card; * The V4L API spec does not define any particular unit for the signal * strength value. These values are in microvolts of RF at the tuner's input. */ -static __u16 sigtable[2][4] = { - { 5, 10, 30, 150 }, - { 28, 40, 63, 1000 } +static u16 sigtable[2][4] = { + { 1835, 2621, 4128, 65535 }, + { 2185, 4369, 13107, 65535 }, }; @@ -91,14 +95,12 @@ static int cadet_getstereo(struct cadet *dev) { int ret = V4L2_TUNER_SUB_MONO; - if (dev->curtuner != 0) /* Only FM has stereo capability! */ + if (!dev->is_fm_band) /* Only FM has stereo capability! */ return V4L2_TUNER_SUB_MONO; - mutex_lock(&dev->lock); outb(7, dev->io); /* Select tuner control */ if ((inb(dev->io + 1) & 0x40) == 0) ret = V4L2_TUNER_SUB_STEREO; - mutex_unlock(&dev->lock); return ret; } @@ -111,8 +113,6 @@ static unsigned cadet_gettune(struct cadet *dev) * Prepare for read */ - mutex_lock(&dev->lock); - outb(7, dev->io); /* Select tuner control */ curvol = inb(dev->io + 1); /* Save current volume/mute setting */ outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */ @@ -134,8 +134,6 @@ static unsigned cadet_gettune(struct cadet *dev) * Restore volume/mute setting */ outb(curvol, dev->io + 1); - mutex_unlock(&dev->lock); - return fifo; } @@ -152,20 +150,18 @@ static unsigned cadet_getfreq(struct cadet *dev) /* * Convert to actual frequency */ - if (dev->curtuner == 0) { /* FM */ - test = 12500; - for (i = 0; i < 14; i++) { - if ((fifo & 0x01) != 0) - freq += test; - test = test << 1; - fifo = fifo >> 1; - } - freq -= 10700000; /* IF frequency is 10.7 MHz */ - freq = (freq * 16) / 1000000; /* Make it 1/16 MHz */ + if (!dev->is_fm_band) /* AM */ + return ((fifo & 0x7fff) - 450) * 16; + + test = 12500; + for (i = 0; i < 14; i++) { + if ((fifo & 0x01) != 0) + freq += test; + test = test << 1; + fifo = fifo >> 1; } - if (dev->curtuner == 1) /* AM */ - freq = ((fifo & 0x7fff) - 2010) * 16; - + freq -= 10700000; /* IF frequency is 10.7 MHz */ + freq = (freq * 16) / 1000; /* Make it 1/16 kHz */ return freq; } @@ -174,8 +170,6 @@ static void cadet_settune(struct cadet *dev, unsigned fifo) int i; unsigned test; - mutex_lock(&dev->lock); - outb(7, dev->io); /* Select tuner control */ /* * Write the shift register @@ -194,7 +188,6 @@ static void cadet_settune(struct cadet *dev, unsigned fifo) test = 0x1c | ((fifo >> 23) & 0x02); outb(test, dev->io + 1); } - mutex_unlock(&dev->lock); } static void cadet_setfreq(struct cadet *dev, unsigned freq) @@ -203,13 +196,14 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) int i, j, test; int curvol; + dev->curfreq = freq; /* * Formulate a fifo command */ fifo = 0; - if (dev->curtuner == 0) { /* FM */ + if (dev->is_fm_band) { /* FM */ test = 102400; - freq = (freq * 1000) / 16; /* Make it kHz */ + freq = freq / 16; /* Make it kHz */ freq += 10700; /* IF is 10700 kHz */ for (i = 0; i < 14; i++) { fifo = fifo << 1; @@ -219,20 +213,17 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) } test = test >> 1; } - } - if (dev->curtuner == 1) { /* AM */ - fifo = (freq / 16) + 2010; /* Make it kHz */ - fifo |= 0x100000; /* Select AM Band */ + } else { /* AM */ + fifo = (freq / 16) + 450; /* Make it kHz */ + fifo |= 0x100000; /* Select AM Band */ } /* * Save current volume/mute setting */ - mutex_lock(&dev->lock); outb(7, dev->io); /* Select tuner control */ curvol = inb(dev->io + 1); - mutex_unlock(&dev->lock); /* * Tune the card @@ -240,49 +231,24 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) for (j = 3; j > -1; j--) { cadet_settune(dev, fifo | (j << 16)); - mutex_lock(&dev->lock); outb(7, dev->io); /* Select tuner control */ outb(curvol, dev->io + 1); - mutex_unlock(&dev->lock); msleep(100); cadet_gettune(dev); if ((dev->tunestat & 0x40) == 0) { /* Tuned */ - dev->sigstrength = sigtable[dev->curtuner][j]; - return; + dev->sigstrength = sigtable[dev->is_fm_band][j]; + goto reset_rds; } } dev->sigstrength = 0; +reset_rds: + outb(3, dev->io); + outb(inb(dev->io + 1) & 0x7f, dev->io + 1); } -static int cadet_getvol(struct cadet *dev) -{ - int ret = 0; - - mutex_lock(&dev->lock); - - outb(7, dev->io); /* Select tuner control */ - if ((inb(dev->io + 1) & 0x20) != 0) - ret = 0xffff; - - mutex_unlock(&dev->lock); - return ret; -} - - -static void cadet_setvol(struct cadet *dev, int vol) -{ - mutex_lock(&dev->lock); - outb(7, dev->io); /* Select tuner control */ - if (vol > 0) - outb(0x20, dev->io + 1); - else - outb(0x00, dev->io + 1); - mutex_unlock(&dev->lock); -} - static void cadet_handler(unsigned long data) { struct cadet *dev = (void *)data; @@ -295,7 +261,7 @@ static void cadet_handler(unsigned long data) outb(0x80, dev->io); /* Select RDS fifo */ while ((inb(dev->io) & 0x80) != 0) { dev->rdsbuf[dev->rdsin] = inb(dev->io + 1); - if (dev->rdsin == dev->rdsout) + if (dev->rdsin + 1 == dev->rdsout) printk(KERN_WARNING "cadet: RDS buffer overflow\n"); else dev->rdsin++; @@ -314,11 +280,21 @@ static void cadet_handler(unsigned long data) */ init_timer(&dev->readtimer); dev->readtimer.function = cadet_handler; - dev->readtimer.data = (unsigned long)0; + dev->readtimer.data = data; dev->readtimer.expires = jiffies + msecs_to_jiffies(50); add_timer(&dev->readtimer); } +static void cadet_start_rds(struct cadet *dev) +{ + dev->rdsstat = 1; + outb(0x80, dev->io); /* Select RDS fifo */ + init_timer(&dev->readtimer); + dev->readtimer.function = cadet_handler; + dev->readtimer.data = (unsigned long)dev; + dev->readtimer.expires = jiffies + msecs_to_jiffies(50); + add_timer(&dev->readtimer); +} static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { @@ -327,28 +303,24 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo int i = 0; mutex_lock(&dev->lock); - if (dev->rdsstat == 0) { - dev->rdsstat = 1; - outb(0x80, dev->io); /* Select RDS fifo */ - init_timer(&dev->readtimer); - dev->readtimer.function = cadet_handler; - dev->readtimer.data = (unsigned long)dev; - dev->readtimer.expires = jiffies + msecs_to_jiffies(50); - add_timer(&dev->readtimer); - } + if (dev->rdsstat == 0) + cadet_start_rds(dev); if (dev->rdsin == dev->rdsout) { + if (file->f_flags & O_NONBLOCK) { + i = -EWOULDBLOCK; + goto unlock; + } mutex_unlock(&dev->lock); - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; interruptible_sleep_on(&dev->read_queue); mutex_lock(&dev->lock); } while (i < count && dev->rdsin != dev->rdsout) readbuf[i++] = dev->rdsbuf[dev->rdsout++]; - mutex_unlock(&dev->lock); - if (copy_to_user(data, readbuf, i)) - return -EFAULT; + if (i && copy_to_user(data, readbuf, i)) + i = -EFAULT; +unlock: + mutex_unlock(&dev->lock); return i; } @@ -359,48 +331,58 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "ADS Cadet", sizeof(v->driver)); strlcpy(v->card, "ADS Cadet", sizeof(v->card)); strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } +static const struct v4l2_frequency_band bands[] = { + { + .index = 0, + .type = V4L2_TUNER_RADIO, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 8320, /* 520 kHz */ + .rangehigh = 26400, /* 1650 kHz */ + .modulation = V4L2_BAND_MODULATION_AM, + }, { + .index = 1, + .type = V4L2_TUNER_RADIO, + .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW | + V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 1400000, /* 87.5 MHz */ + .rangehigh = 1728000, /* 108.0 MHz */ + .modulation = V4L2_BAND_MODULATION_FM, + }, +}; + static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { struct cadet *dev = video_drvdata(file); + if (v->index) + return -EINVAL; v->type = V4L2_TUNER_RADIO; - switch (v->index) { - case 0: - strlcpy(v->name, "FM", sizeof(v->name)); - v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_RDS_BLOCK_IO; - v->rangelow = 1400; /* 87.5 MHz */ - v->rangehigh = 1728; /* 108.0 MHz */ + strlcpy(v->name, "Radio", sizeof(v->name)); + v->capability = bands[0].capability | bands[1].capability; + v->rangelow = bands[0].rangelow; /* 520 kHz (start of AM band) */ + v->rangehigh = bands[1].rangehigh; /* 108.0 MHz (end of FM band) */ + if (dev->is_fm_band) { v->rxsubchans = cadet_getstereo(dev); - switch (v->rxsubchans) { - case V4L2_TUNER_SUB_MONO: - v->audmode = V4L2_TUNER_MODE_MONO; - break; - case V4L2_TUNER_SUB_STEREO: - v->audmode = V4L2_TUNER_MODE_STEREO; - break; - default: - break; - } - v->rxsubchans |= V4L2_TUNER_SUB_RDS; - break; - case 1: - strlcpy(v->name, "AM", sizeof(v->name)); - v->capability = V4L2_TUNER_CAP_LOW; + outb(3, dev->io); + outb(inb(dev->io + 1) & 0x7f, dev->io + 1); + mdelay(100); + outb(3, dev->io); + if (inb(dev->io + 1) & 0x80) + v->rxsubchans |= V4L2_TUNER_SUB_RDS; + } else { v->rangelow = 8320; /* 520 kHz */ v->rangehigh = 26400; /* 1650 kHz */ v->rxsubchans = V4L2_TUNER_SUB_MONO; - v->audmode = V4L2_TUNER_MODE_MONO; - break; - default: - return -EINVAL; } + v->audmode = V4L2_TUNER_MODE_STEREO; v->signal = dev->sigstrength; /* We might need to modify scaling of this */ return 0; } @@ -408,11 +390,17 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct cadet *dev = video_drvdata(file); + return v->index ? -EINVAL : 0; +} - if (v->index != 0 && v->index != 1) +static int vidioc_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + if (band->tuner) + return -EINVAL; + if (band->index >= ARRAY_SIZE(bands)) return -EINVAL; - dev->curtuner = v->index; + *band = bands[band->index]; return 0; } @@ -421,9 +409,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct cadet *dev = video_drvdata(file); - f->tuner = dev->curtuner; + if (f->tuner) + return -EINVAL; f->type = V4L2_TUNER_RADIO; - f->frequency = cadet_getfreq(dev); + f->frequency = dev->curfreq; return 0; } @@ -433,103 +422,46 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct cadet *dev = video_drvdata(file); - if (f->type != V4L2_TUNER_RADIO) - return -EINVAL; - if (dev->curtuner == 0 && (f->frequency < 1400 || f->frequency > 1728)) - return -EINVAL; - if (dev->curtuner == 1 && (f->frequency < 8320 || f->frequency > 26400)) + if (f->tuner) return -EINVAL; + dev->is_fm_band = + f->frequency >= (bands[0].rangehigh + bands[1].rangelow) / 2; + clamp(f->frequency, bands[dev->is_fm_band].rangelow, + bands[dev->is_fm_band].rangehigh); cadet_setfreq(dev, f->frequency); return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int cadet_s_ctrl(struct v4l2_ctrl *ctrl) { - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct cadet *dev = video_drvdata(file); + struct cadet *dev = container_of(ctrl->handler, struct cadet, ctrl_handler); switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ - ctrl->value = (cadet_getvol(dev) == 0); - break; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = cadet_getvol(dev); - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct cadet *dev = video_drvdata(file); - - switch (ctrl->id){ - case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ - if (ctrl->value) - cadet_setvol(dev, 0); + case V4L2_CID_AUDIO_MUTE: + outb(7, dev->io); /* Select tuner control */ + if (ctrl->val) + outb(0x00, dev->io + 1); else - cadet_setvol(dev, 0xffff); - break; - case V4L2_CID_AUDIO_VOLUME: - cadet_setvol(dev, ctrl->value); - break; - default: - return -EINVAL; + outb(0x20, dev->io + 1); + return 0; } - return 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; + return -EINVAL; } static int cadet_open(struct file *file) { struct cadet *dev = video_drvdata(file); + int err; mutex_lock(&dev->lock); - dev->users++; - if (1 == dev->users) + err = v4l2_fh_open(file); + if (err) + goto fail; + if (v4l2_fh_is_singular_file(file)) init_waitqueue_head(&dev->read_queue); +fail: mutex_unlock(&dev->lock); - return 0; + return err; } static int cadet_release(struct file *file) @@ -537,11 +469,11 @@ static int cadet_release(struct file *file) struct cadet *dev = video_drvdata(file); mutex_lock(&dev->lock); - dev->users--; - if (0 == dev->users) { + if (v4l2_fh_is_singular_file(file) && dev->rdsstat) { del_timer_sync(&dev->readtimer); dev->rdsstat = 0; } + v4l2_fh_release(file); mutex_unlock(&dev->lock); return 0; } @@ -549,11 +481,19 @@ static int cadet_release(struct file *file) static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) { struct cadet *dev = video_drvdata(file); + unsigned long req_events = poll_requested_events(wait); + unsigned int res = v4l2_ctrl_poll(file, wait); poll_wait(file, &dev->read_queue, wait); + if (dev->rdsstat == 0 && (req_events & (POLLIN | POLLRDNORM))) { + mutex_lock(&dev->lock); + if (dev->rdsstat == 0) + cadet_start_rds(dev); + mutex_unlock(&dev->lock); + } if (dev->rdsin != dev->rdsout) - return POLLIN | POLLRDNORM; - return 0; + res |= POLLIN | POLLRDNORM; + return res; } @@ -572,13 +512,14 @@ static const struct v4l2_ioctl_ops cadet_ioctl_ops = { .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, + .vidioc_enum_freq_bands = vidioc_enum_freq_bands, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_ctrl_ops cadet_ctrl_ops = { + .s_ctrl = cadet_s_ctrl, }; #ifdef CONFIG_PNP @@ -628,8 +569,8 @@ static void cadet_probe(struct cadet *dev) for (i = 0; i < 8; i++) { dev->io = iovals[i]; if (request_region(dev->io, 2, "cadet-probe")) { - cadet_setfreq(dev, 1410); - if (cadet_getfreq(dev) == 1410) { + cadet_setfreq(dev, bands[1].rangelow); + if (cadet_getfreq(dev) == bands[1].rangelow) { release_region(dev->io, 2); return; } @@ -648,7 +589,8 @@ static int __init cadet_init(void) { struct cadet *dev = &cadet_card; struct v4l2_device *v4l2_dev = &dev->v4l2_dev; - int res; + struct v4l2_ctrl_handler *hdl; + int res = -ENODEV; strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name)); mutex_init(&dev->lock); @@ -680,23 +622,40 @@ static int __init cadet_init(void) goto fail; } + hdl = &dev->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 2); + v4l2_ctrl_new_std(hdl, &cadet_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + v4l2_dev->ctrl_handler = hdl; + if (hdl->error) { + res = hdl->error; + v4l2_err(v4l2_dev, "Could not register controls\n"); + goto err_hdl; + } + + dev->is_fm_band = true; + dev->curfreq = bands[dev->is_fm_band].rangelow; + cadet_setfreq(dev, dev->curfreq); strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); dev->vdev.v4l2_dev = v4l2_dev; dev->vdev.fops = &cadet_fops; dev->vdev.ioctl_ops = &cadet_ioctl_ops; dev->vdev.release = video_device_release_empty; + dev->vdev.lock = &dev->lock; + set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); video_set_drvdata(&dev->vdev, dev); - if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(dev->io, 2); - goto fail; - } + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) + goto err_hdl; v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io); return 0; +err_hdl: + v4l2_ctrl_handler_free(hdl); + v4l2_device_unregister(v4l2_dev); + release_region(dev->io, 2); fail: pnp_unregister_driver(&cadet_pnp_driver); - return -ENODEV; + return res; } static void __exit cadet_exit(void) @@ -704,7 +663,10 @@ static void __exit cadet_exit(void) struct cadet *dev = &cadet_card; video_unregister_device(&dev->vdev); + v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_device_unregister(&dev->v4l2_dev); + outb(7, dev->io); /* Mute */ + outb(0x00, dev->io + 1); release_region(dev->io, 2); pnp_unregister_driver(&cadet_pnp_driver); } diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 94cb6bc690f5..3182b26d6efa 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -295,7 +295,8 @@ static int vidioc_g_tuner(struct file *file, void *priv, v->type = V4L2_TUNER_RADIO; v->rangelow = FREQ_MIN * FREQ_MUL; v->rangehigh = FREQ_MAX * FREQ_MUL; - v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_HWSEEK_WRAP; v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; v->audmode = radio->stereo ? V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO; @@ -372,7 +373,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *priv, timeout = jiffies + msecs_to_jiffies(30000); for (;;) { if (time_after(jiffies, timeout)) { - retval = -EAGAIN; + retval = -ENODATA; break; } if (schedule_timeout_interruptible(msecs_to_jiffies(10))) { diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index a81d723b8c77..8185d5fbfa89 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -27,6 +27,7 @@ #include <linux/io.h> /* outb, outb_p */ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include "lm7000.h" MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); MODULE_DESCRIPTION("A driver for the SF16-FMI, SF16-FMP and SF16-FMD radio."); @@ -54,31 +55,33 @@ static struct fmi fmi_card; static struct pnp_dev *dev; bool pnp_attached; -/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ -/* It is only useful to give freq in interval of 800 (=0.05Mhz), - * other bits will be truncated, e.g 92.7400016 -> 92.7, but - * 92.7400017 -> 92.75 - */ -#define RSF16_ENCODE(x) ((x) / 800 + 214) #define RSF16_MINFREQ (87 * 16000) #define RSF16_MAXFREQ (108 * 16000) -static void outbits(int bits, unsigned int data, int io) +#define FMI_BIT_TUN_CE (1 << 0) +#define FMI_BIT_TUN_CLK (1 << 1) +#define FMI_BIT_TUN_DATA (1 << 2) +#define FMI_BIT_VOL_SW (1 << 3) +#define FMI_BIT_TUN_STRQ (1 << 4) + +void fmi_set_pins(void *handle, u8 pins) { - while (bits--) { - if (data & 1) { - outb(5, io); - udelay(6); - outb(7, io); - udelay(6); - } else { - outb(1, io); - udelay(6); - outb(3, io); - udelay(6); - } - data >>= 1; - } + struct fmi *fmi = handle; + u8 bits = FMI_BIT_TUN_STRQ; + + if (!fmi->mute) + bits |= FMI_BIT_VOL_SW; + + if (pins & LM7000_DATA) + bits |= FMI_BIT_TUN_DATA; + if (pins & LM7000_CLK) + bits |= FMI_BIT_TUN_CLK; + if (pins & LM7000_CE) + bits |= FMI_BIT_TUN_CE; + + mutex_lock(&fmi->lock); + outb_p(bits, fmi->io); + mutex_unlock(&fmi->lock); } static inline void fmi_mute(struct fmi *fmi) @@ -95,20 +98,6 @@ static inline void fmi_unmute(struct fmi *fmi) mutex_unlock(&fmi->lock); } -static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq) -{ - mutex_lock(&fmi->lock); - fmi->curfreq = freq; - - outbits(16, RSF16_ENCODE(freq), fmi->io); - outbits(8, 0xC0, fmi->io); - msleep(143); /* was schedule_timeout(HZ/7) */ - mutex_unlock(&fmi->lock); - if (!fmi->mute) - fmi_unmute(fmi); - return 0; -} - static inline int fmi_getsigstr(struct fmi *fmi) { int val; @@ -173,7 +162,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, return -EINVAL; /* rounding in steps of 800 to match the freq that will be used */ - fmi_setfreq(fmi, (f->frequency / 800) * 800); + lm7000_set_freq((f->frequency / 800) * 800, fmi, fmi_set_pins); return 0; } diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c new file mode 100644 index 000000000000..d0b6bb507634 --- /dev/null +++ b/drivers/media/radio/radio-shark.c @@ -0,0 +1,376 @@ +/* + * Linux V4L2 radio driver for the Griffin radioSHARK USB radio receiver + * + * Note the radioSHARK offers the audio through a regular USB audio device, + * this driver only handles the tuning. + * + * The info necessary to drive the shark was taken from the small userspace + * shark.c program by Michael Rolig, which he kindly placed in the Public + * Domain. + * + * Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/workqueue.h> +#include <media/v4l2-device.h> +#include <sound/tea575x-tuner.h> + +/* + * Version Information + */ +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_DESCRIPTION("Griffin radioSHARK, USB radio receiver driver"); +MODULE_LICENSE("GPL"); + +#define SHARK_IN_EP 0x83 +#define SHARK_OUT_EP 0x05 + +#define TEA575X_BIT_MONO (1<<22) /* 0 = stereo, 1 = mono */ +#define TEA575X_BIT_BAND_MASK (3<<20) +#define TEA575X_BIT_BAND_FM (0<<20) + +#define TB_LEN 6 +#define DRV_NAME "radioshark" + +#define v4l2_dev_to_shark(d) container_of(d, struct shark_device, v4l2_dev) + +enum { BLUE_LED, BLUE_PULSE_LED, RED_LED, NO_LEDS }; + +static void shark_led_set_blue(struct led_classdev *led_cdev, + enum led_brightness value); +static void shark_led_set_blue_pulse(struct led_classdev *led_cdev, + enum led_brightness value); +static void shark_led_set_red(struct led_classdev *led_cdev, + enum led_brightness value); + +static const struct led_classdev shark_led_templates[NO_LEDS] = { + [BLUE_LED] = { + .name = "%s:blue:", + .brightness = LED_OFF, + .max_brightness = 127, + .brightness_set = shark_led_set_blue, + }, + [BLUE_PULSE_LED] = { + .name = "%s:blue-pulse:", + .brightness = LED_OFF, + .max_brightness = 255, + .brightness_set = shark_led_set_blue_pulse, + }, + [RED_LED] = { + .name = "%s:red:", + .brightness = LED_OFF, + .max_brightness = 1, + .brightness_set = shark_led_set_red, + }, +}; + +struct shark_device { + struct usb_device *usbdev; + struct v4l2_device v4l2_dev; + struct snd_tea575x tea; + + struct work_struct led_work; + struct led_classdev leds[NO_LEDS]; + char led_names[NO_LEDS][32]; + atomic_t brightness[NO_LEDS]; + unsigned long brightness_new; + + u8 *transfer_buffer; + u32 last_val; +}; + +static atomic_t shark_instance = ATOMIC_INIT(0); + +static void shark_write_val(struct snd_tea575x *tea, u32 val) +{ + struct shark_device *shark = tea->private_data; + int i, res, actual_len; + + /* Avoid unnecessary (slow) USB transfers */ + if (shark->last_val == val) + return; + + memset(shark->transfer_buffer, 0, TB_LEN); + shark->transfer_buffer[0] = 0xc0; /* Write shift register command */ + for (i = 0; i < 4; i++) + shark->transfer_buffer[i] |= (val >> (24 - i * 8)) & 0xff; + + res = usb_interrupt_msg(shark->usbdev, + usb_sndintpipe(shark->usbdev, SHARK_OUT_EP), + shark->transfer_buffer, TB_LEN, + &actual_len, 1000); + if (res >= 0) + shark->last_val = val; + else + v4l2_err(&shark->v4l2_dev, "set-freq error: %d\n", res); +} + +static u32 shark_read_val(struct snd_tea575x *tea) +{ + struct shark_device *shark = tea->private_data; + int i, res, actual_len; + u32 val = 0; + + memset(shark->transfer_buffer, 0, TB_LEN); + shark->transfer_buffer[0] = 0x80; + res = usb_interrupt_msg(shark->usbdev, + usb_sndintpipe(shark->usbdev, SHARK_OUT_EP), + shark->transfer_buffer, TB_LEN, + &actual_len, 1000); + if (res < 0) { + v4l2_err(&shark->v4l2_dev, "request-status error: %d\n", res); + return shark->last_val; + } + + res = usb_interrupt_msg(shark->usbdev, + usb_rcvintpipe(shark->usbdev, SHARK_IN_EP), + shark->transfer_buffer, TB_LEN, + &actual_len, 1000); + if (res < 0) { + v4l2_err(&shark->v4l2_dev, "get-status error: %d\n", res); + return shark->last_val; + } + + for (i = 0; i < 4; i++) + val |= shark->transfer_buffer[i] << (24 - i * 8); + + shark->last_val = val; + + /* + * The shark does not allow actually reading the stereo / mono pin :( + * So assume that when we're tuned to an FM station and mono has not + * been requested, that we're receiving stereo. + */ + if (((val & TEA575X_BIT_BAND_MASK) == TEA575X_BIT_BAND_FM) && + !(val & TEA575X_BIT_MONO)) + shark->tea.stereo = true; + else + shark->tea.stereo = false; + + return val; +} + +static struct snd_tea575x_ops shark_tea_ops = { + .write_val = shark_write_val, + .read_val = shark_read_val, +}; + +static void shark_led_work(struct work_struct *work) +{ + struct shark_device *shark = + container_of(work, struct shark_device, led_work); + int i, res, brightness, actual_len; + + /* + * We use the v4l2_dev lock and registered bit to ensure the device + * does not get unplugged and unreffed while we're running. + */ + mutex_lock(&shark->tea.mutex); + if (!video_is_registered(&shark->tea.vd)) + goto leave; + + for (i = 0; i < 3; i++) { + if (!test_and_clear_bit(i, &shark->brightness_new)) + continue; + + brightness = atomic_read(&shark->brightness[i]); + memset(shark->transfer_buffer, 0, TB_LEN); + if (i != RED_LED) { + shark->transfer_buffer[0] = 0xA0 + i; + shark->transfer_buffer[1] = brightness; + } else + shark->transfer_buffer[0] = brightness ? 0xA9 : 0xA8; + res = usb_interrupt_msg(shark->usbdev, + usb_sndintpipe(shark->usbdev, 0x05), + shark->transfer_buffer, TB_LEN, + &actual_len, 1000); + if (res < 0) + v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n", + shark->led_names[i], res); + } +leave: + mutex_unlock(&shark->tea.mutex); +} + +static void shark_led_set_blue(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct shark_device *shark = + container_of(led_cdev, struct shark_device, leds[BLUE_LED]); + + atomic_set(&shark->brightness[BLUE_LED], value); + set_bit(BLUE_LED, &shark->brightness_new); + schedule_work(&shark->led_work); +} + +static void shark_led_set_blue_pulse(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct shark_device *shark = container_of(led_cdev, + struct shark_device, leds[BLUE_PULSE_LED]); + + atomic_set(&shark->brightness[BLUE_PULSE_LED], 256 - value); + set_bit(BLUE_PULSE_LED, &shark->brightness_new); + schedule_work(&shark->led_work); +} + +static void shark_led_set_red(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct shark_device *shark = + container_of(led_cdev, struct shark_device, leds[RED_LED]); + + atomic_set(&shark->brightness[RED_LED], value); + set_bit(RED_LED, &shark->brightness_new); + schedule_work(&shark->led_work); +} + +static void usb_shark_disconnect(struct usb_interface *intf) +{ + struct v4l2_device *v4l2_dev = usb_get_intfdata(intf); + struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev); + int i; + + mutex_lock(&shark->tea.mutex); + v4l2_device_disconnect(&shark->v4l2_dev); + snd_tea575x_exit(&shark->tea); + mutex_unlock(&shark->tea.mutex); + + for (i = 0; i < NO_LEDS; i++) + led_classdev_unregister(&shark->leds[i]); + + v4l2_device_put(&shark->v4l2_dev); +} + +static void usb_shark_release(struct v4l2_device *v4l2_dev) +{ + struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev); + + cancel_work_sync(&shark->led_work); + v4l2_device_unregister(&shark->v4l2_dev); + kfree(shark->transfer_buffer); + kfree(shark); +} + +static int usb_shark_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct shark_device *shark; + int i, retval = -ENOMEM; + + shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL); + if (!shark) + return retval; + + shark->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL); + if (!shark->transfer_buffer) + goto err_alloc_buffer; + + /* + * Work around a bug in usbhid/hid-core.c, where it leaves a dangling + * pointer in intfdata causing v4l2-device.c to not set it. Which + * results in usb_shark_disconnect() referencing the dangling pointer + * + * REMOVE (as soon as the above bug is fixed, patch submitted) + */ + usb_set_intfdata(intf, NULL); + + shark->v4l2_dev.release = usb_shark_release; + v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance); + retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev); + if (retval) { + v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n"); + goto err_reg_dev; + } + + shark->usbdev = interface_to_usbdev(intf); + shark->tea.v4l2_dev = &shark->v4l2_dev; + shark->tea.private_data = shark; + shark->tea.radio_nr = -1; + shark->tea.ops = &shark_tea_ops; + shark->tea.cannot_mute = true; + strlcpy(shark->tea.card, "Griffin radioSHARK", + sizeof(shark->tea.card)); + usb_make_path(shark->usbdev, shark->tea.bus_info, + sizeof(shark->tea.bus_info)); + + retval = snd_tea575x_init(&shark->tea, THIS_MODULE); + if (retval) { + v4l2_err(&shark->v4l2_dev, "couldn't init tea5757\n"); + goto err_init_tea; + } + + INIT_WORK(&shark->led_work, shark_led_work); + for (i = 0; i < NO_LEDS; i++) { + shark->leds[i] = shark_led_templates[i]; + snprintf(shark->led_names[i], sizeof(shark->led_names[0]), + shark->leds[i].name, shark->v4l2_dev.name); + shark->leds[i].name = shark->led_names[i]; + /* + * We don't fail the probe if we fail to register the leds, + * because once we've called snd_tea575x_init, the /dev/radio0 + * node may be opened from userspace holding a reference to us! + * + * Note we cannot register the leds first instead as + * shark_led_work depends on the v4l2 mutex and registered bit. + */ + retval = led_classdev_register(&intf->dev, &shark->leds[i]); + if (retval) + v4l2_err(&shark->v4l2_dev, + "couldn't register led: %s\n", + shark->led_names[i]); + } + + return 0; + +err_init_tea: + v4l2_device_unregister(&shark->v4l2_dev); +err_reg_dev: + kfree(shark->transfer_buffer); +err_alloc_buffer: + kfree(shark); + + return retval; +} + +/* Specify the bcdDevice value, as the radioSHARK and radioSHARK2 share ids */ +static struct usb_device_id usb_shark_device_table[] = { + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | + USB_DEVICE_ID_MATCH_INT_CLASS, + .idVendor = 0x077d, + .idProduct = 0x627a, + .bcdDevice_lo = 0x0001, + .bcdDevice_hi = 0x0001, + .bInterfaceClass = 3, + }, + { } +}; +MODULE_DEVICE_TABLE(usb, usb_shark_device_table); + +static struct usb_driver usb_shark_driver = { + .name = DRV_NAME, + .probe = usb_shark_probe, + .disconnect = usb_shark_disconnect, + .id_table = usb_shark_device_table, +}; +module_usb_driver(usb_shark_driver); diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c new file mode 100644 index 000000000000..b9575de3e7e8 --- /dev/null +++ b/drivers/media/radio/radio-shark2.c @@ -0,0 +1,348 @@ +/* + * Linux V4L2 radio driver for the Griffin radioSHARK2 USB radio receiver + * + * Note the radioSHARK2 offers the audio through a regular USB audio device, + * this driver only handles the tuning. + * + * The info necessary to drive the shark2 was taken from the small userspace + * shark2.c program by Hisaaki Shibata, which he kindly placed in the Public + * Domain. + * + * Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/workqueue.h> +#include <media/v4l2-device.h> +#include "radio-tea5777.h" + +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_DESCRIPTION("Griffin radioSHARK2, USB radio receiver driver"); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + + +#define SHARK_IN_EP 0x83 +#define SHARK_OUT_EP 0x05 + +#define TB_LEN 7 +#define DRV_NAME "radioshark2" + +#define v4l2_dev_to_shark(d) container_of(d, struct shark_device, v4l2_dev) + +enum { BLUE_LED, RED_LED, NO_LEDS }; + +static void shark_led_set_blue(struct led_classdev *led_cdev, + enum led_brightness value); +static void shark_led_set_red(struct led_classdev *led_cdev, + enum led_brightness value); + +static const struct led_classdev shark_led_templates[NO_LEDS] = { + [BLUE_LED] = { + .name = "%s:blue:", + .brightness = LED_OFF, + .max_brightness = 127, + .brightness_set = shark_led_set_blue, + }, + [RED_LED] = { + .name = "%s:red:", + .brightness = LED_OFF, + .max_brightness = 1, + .brightness_set = shark_led_set_red, + }, +}; + +struct shark_device { + struct usb_device *usbdev; + struct v4l2_device v4l2_dev; + struct radio_tea5777 tea; + + struct work_struct led_work; + struct led_classdev leds[NO_LEDS]; + char led_names[NO_LEDS][32]; + atomic_t brightness[NO_LEDS]; + unsigned long brightness_new; + + u8 *transfer_buffer; +}; + +static atomic_t shark_instance = ATOMIC_INIT(0); + +static int shark_write_reg(struct radio_tea5777 *tea, u64 reg) +{ + struct shark_device *shark = tea->private_data; + int i, res, actual_len; + + memset(shark->transfer_buffer, 0, TB_LEN); + shark->transfer_buffer[0] = 0x81; /* Write register command */ + for (i = 0; i < 6; i++) + shark->transfer_buffer[i + 1] = (reg >> (40 - i * 8)) & 0xff; + + v4l2_dbg(1, debug, tea->v4l2_dev, + "shark2-write: %02x %02x %02x %02x %02x %02x %02x\n", + shark->transfer_buffer[0], shark->transfer_buffer[1], + shark->transfer_buffer[2], shark->transfer_buffer[3], + shark->transfer_buffer[4], shark->transfer_buffer[5], + shark->transfer_buffer[6]); + + res = usb_interrupt_msg(shark->usbdev, + usb_sndintpipe(shark->usbdev, SHARK_OUT_EP), + shark->transfer_buffer, TB_LEN, + &actual_len, 1000); + if (res < 0) { + v4l2_err(tea->v4l2_dev, "write error: %d\n", res); + return res; + } + + return 0; +} + +static int shark_read_reg(struct radio_tea5777 *tea, u32 *reg_ret) +{ + struct shark_device *shark = tea->private_data; + int i, res, actual_len; + u32 reg = 0; + + memset(shark->transfer_buffer, 0, TB_LEN); + shark->transfer_buffer[0] = 0x82; + res = usb_interrupt_msg(shark->usbdev, + usb_sndintpipe(shark->usbdev, SHARK_OUT_EP), + shark->transfer_buffer, TB_LEN, + &actual_len, 1000); + if (res < 0) { + v4l2_err(tea->v4l2_dev, "request-read error: %d\n", res); + return res; + } + + res = usb_interrupt_msg(shark->usbdev, + usb_rcvintpipe(shark->usbdev, SHARK_IN_EP), + shark->transfer_buffer, TB_LEN, + &actual_len, 1000); + if (res < 0) { + v4l2_err(tea->v4l2_dev, "read error: %d\n", res); + return res; + } + + for (i = 0; i < 3; i++) + reg |= shark->transfer_buffer[i] << (16 - i * 8); + + v4l2_dbg(1, debug, tea->v4l2_dev, "shark2-read: %02x %02x %02x\n", + shark->transfer_buffer[0], shark->transfer_buffer[1], + shark->transfer_buffer[2]); + + *reg_ret = reg; + return 0; +} + +static struct radio_tea5777_ops shark_tea_ops = { + .write_reg = shark_write_reg, + .read_reg = shark_read_reg, +}; + +static void shark_led_work(struct work_struct *work) +{ + struct shark_device *shark = + container_of(work, struct shark_device, led_work); + int i, res, brightness, actual_len; + /* + * We use the v4l2_dev lock and registered bit to ensure the device + * does not get unplugged and unreffed while we're running. + */ + mutex_lock(&shark->tea.mutex); + if (!video_is_registered(&shark->tea.vd)) + goto leave; + + for (i = 0; i < 2; i++) { + if (!test_and_clear_bit(i, &shark->brightness_new)) + continue; + + brightness = atomic_read(&shark->brightness[i]); + memset(shark->transfer_buffer, 0, TB_LEN); + shark->transfer_buffer[0] = 0x83 + i; + shark->transfer_buffer[1] = brightness; + res = usb_interrupt_msg(shark->usbdev, + usb_sndintpipe(shark->usbdev, + SHARK_OUT_EP), + shark->transfer_buffer, TB_LEN, + &actual_len, 1000); + if (res < 0) + v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n", + shark->led_names[i], res); + } +leave: + mutex_unlock(&shark->tea.mutex); +} + +static void shark_led_set_blue(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct shark_device *shark = + container_of(led_cdev, struct shark_device, leds[BLUE_LED]); + + atomic_set(&shark->brightness[BLUE_LED], value); + set_bit(BLUE_LED, &shark->brightness_new); + schedule_work(&shark->led_work); +} + +static void shark_led_set_red(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct shark_device *shark = + container_of(led_cdev, struct shark_device, leds[RED_LED]); + + atomic_set(&shark->brightness[RED_LED], value); + set_bit(RED_LED, &shark->brightness_new); + schedule_work(&shark->led_work); +} + +static void usb_shark_disconnect(struct usb_interface *intf) +{ + struct v4l2_device *v4l2_dev = usb_get_intfdata(intf); + struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev); + int i; + + mutex_lock(&shark->tea.mutex); + v4l2_device_disconnect(&shark->v4l2_dev); + radio_tea5777_exit(&shark->tea); + mutex_unlock(&shark->tea.mutex); + + for (i = 0; i < NO_LEDS; i++) + led_classdev_unregister(&shark->leds[i]); + + v4l2_device_put(&shark->v4l2_dev); +} + +static void usb_shark_release(struct v4l2_device *v4l2_dev) +{ + struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev); + + cancel_work_sync(&shark->led_work); + v4l2_device_unregister(&shark->v4l2_dev); + kfree(shark->transfer_buffer); + kfree(shark); +} + +static int usb_shark_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct shark_device *shark; + int i, retval = -ENOMEM; + + shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL); + if (!shark) + return retval; + + shark->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL); + if (!shark->transfer_buffer) + goto err_alloc_buffer; + + /* + * Work around a bug in usbhid/hid-core.c, where it leaves a dangling + * pointer in intfdata causing v4l2-device.c to not set it. Which + * results in usb_shark_disconnect() referencing the dangling pointer + * + * REMOVE (as soon as the above bug is fixed, patch submitted) + */ + usb_set_intfdata(intf, NULL); + + shark->v4l2_dev.release = usb_shark_release; + v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance); + retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev); + if (retval) { + v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n"); + goto err_reg_dev; + } + + shark->usbdev = interface_to_usbdev(intf); + shark->tea.v4l2_dev = &shark->v4l2_dev; + shark->tea.private_data = shark; + shark->tea.ops = &shark_tea_ops; + shark->tea.has_am = true; + shark->tea.write_before_read = true; + strlcpy(shark->tea.card, "Griffin radioSHARK2", + sizeof(shark->tea.card)); + usb_make_path(shark->usbdev, shark->tea.bus_info, + sizeof(shark->tea.bus_info)); + + retval = radio_tea5777_init(&shark->tea, THIS_MODULE); + if (retval) { + v4l2_err(&shark->v4l2_dev, "couldn't init tea5777\n"); + goto err_init_tea; + } + + INIT_WORK(&shark->led_work, shark_led_work); + for (i = 0; i < NO_LEDS; i++) { + shark->leds[i] = shark_led_templates[i]; + snprintf(shark->led_names[i], sizeof(shark->led_names[0]), + shark->leds[i].name, shark->v4l2_dev.name); + shark->leds[i].name = shark->led_names[i]; + /* + * We don't fail the probe if we fail to register the leds, + * because once we've called radio_tea5777_init, the /dev/radio0 + * node may be opened from userspace holding a reference to us! + * + * Note we cannot register the leds first instead as + * shark_led_work depends on the v4l2 mutex and registered bit. + */ + retval = led_classdev_register(&intf->dev, &shark->leds[i]); + if (retval) + v4l2_err(&shark->v4l2_dev, + "couldn't register led: %s\n", + shark->led_names[i]); + } + + return 0; + +err_init_tea: + v4l2_device_unregister(&shark->v4l2_dev); +err_reg_dev: + kfree(shark->transfer_buffer); +err_alloc_buffer: + kfree(shark); + + return retval; +} + +/* Specify the bcdDevice value, as the radioSHARK and radioSHARK2 share ids */ +static struct usb_device_id usb_shark_device_table[] = { + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | + USB_DEVICE_ID_MATCH_INT_CLASS, + .idVendor = 0x077d, + .idProduct = 0x627a, + .bcdDevice_lo = 0x0010, + .bcdDevice_hi = 0x0010, + .bInterfaceClass = 3, + }, + { } +}; +MODULE_DEVICE_TABLE(usb, usb_shark_device_table); + +static struct usb_driver usb_shark_driver = { + .name = DRV_NAME, + .probe = usb_shark_probe, + .disconnect = usb_shark_disconnect, + .id_table = usb_shark_device_table, +}; +module_usb_driver(usb_shark_driver); diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c new file mode 100644 index 000000000000..5bc9fa62720b --- /dev/null +++ b/drivers/media/radio/radio-tea5777.c @@ -0,0 +1,491 @@ +/* + * v4l2 driver for TEA5777 Philips AM/FM radio tuner chips + * + * Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com> + * + * Based on the ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips: + * + * Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include <asm/div64.h> +#include "radio-tea5777.h" + +MODULE_AUTHOR("Hans de Goede <perex@perex.cz>"); +MODULE_DESCRIPTION("Routines for control of TEA5777 Philips AM/FM radio tuner chips"); +MODULE_LICENSE("GPL"); + +/* Fixed FM only band for now, will implement multi-band support when the + VIDIOC_ENUM_FREQ_BANDS API is upstream */ +#define TEA5777_FM_RANGELOW (76000 * 16) +#define TEA5777_FM_RANGEHIGH (108000 * 16) + +#define TEA5777_FM_IF 150 /* kHz */ +#define TEA5777_FM_FREQ_STEP 50 /* kHz */ + +/* Write reg, common bits */ +#define TEA5777_W_MUTE_MASK (1LL << 47) +#define TEA5777_W_MUTE_SHIFT 47 +#define TEA5777_W_AM_FM_MASK (1LL << 46) +#define TEA5777_W_AM_FM_SHIFT 46 +#define TEA5777_W_STB_MASK (1LL << 45) +#define TEA5777_W_STB_SHIFT 45 + +#define TEA5777_W_IFCE_MASK (1LL << 29) +#define TEA5777_W_IFCE_SHIFT 29 +#define TEA5777_W_IFW_MASK (1LL << 28) +#define TEA5777_W_IFW_SHIFT 28 +#define TEA5777_W_HILO_MASK (1LL << 27) +#define TEA5777_W_HILO_SHIFT 27 +#define TEA5777_W_DBUS_MASK (1LL << 26) +#define TEA5777_W_DBUS_SHIFT 26 + +#define TEA5777_W_INTEXT_MASK (1LL << 24) +#define TEA5777_W_INTEXT_SHIFT 24 +#define TEA5777_W_P1_MASK (1LL << 23) +#define TEA5777_W_P1_SHIFT 23 +#define TEA5777_W_P0_MASK (1LL << 22) +#define TEA5777_W_P0_SHIFT 22 +#define TEA5777_W_PEN1_MASK (1LL << 21) +#define TEA5777_W_PEN1_SHIFT 21 +#define TEA5777_W_PEN0_MASK (1LL << 20) +#define TEA5777_W_PEN0_SHIFT 20 + +#define TEA5777_W_CHP0_MASK (1LL << 18) +#define TEA5777_W_CHP0_SHIFT 18 +#define TEA5777_W_DEEM_MASK (1LL << 17) +#define TEA5777_W_DEEM_SHIFT 17 + +#define TEA5777_W_SEARCH_MASK (1LL << 7) +#define TEA5777_W_SEARCH_SHIFT 7 +#define TEA5777_W_PROGBLIM_MASK (1LL << 6) +#define TEA5777_W_PROGBLIM_SHIFT 6 +#define TEA5777_W_UPDWN_MASK (1LL << 5) +#define TEA5777_W_UPDWN_SHIFT 5 +#define TEA5777_W_SLEV_MASK (3LL << 3) +#define TEA5777_W_SLEV_SHIFT 3 + +/* Write reg, FM specific bits */ +#define TEA5777_W_FM_PLL_MASK (0x1fffLL << 32) +#define TEA5777_W_FM_PLL_SHIFT 32 +#define TEA5777_W_FM_FREF_MASK (0x03LL << 30) +#define TEA5777_W_FM_FREF_SHIFT 30 +#define TEA5777_W_FM_FREF_VALUE 0 /* 50 kHz tune steps, 150 kHz IF */ + +#define TEA5777_W_FM_FORCEMONO_MASK (1LL << 15) +#define TEA5777_W_FM_FORCEMONO_SHIFT 15 +#define TEA5777_W_FM_SDSOFF_MASK (1LL << 14) +#define TEA5777_W_FM_SDSOFF_SHIFT 14 +#define TEA5777_W_FM_DOFF_MASK (1LL << 13) +#define TEA5777_W_FM_DOFF_SHIFT 13 + +#define TEA5777_W_FM_STEP_MASK (3LL << 1) +#define TEA5777_W_FM_STEP_SHIFT 1 + +/* Write reg, AM specific bits */ +#define TEA5777_W_AM_PLL_MASK (0x7ffLL << 34) +#define TEA5777_W_AM_PLL_SHIFT 34 +#define TEA5777_W_AM_AGCRF_MASK (1LL << 33) +#define TEA5777_W_AM_AGCRF_SHIFT 33 +#define TEA5777_W_AM_AGCIF_MASK (1LL << 32) +#define TEA5777_W_AM_AGCIF_SHIFT 32 +#define TEA5777_W_AM_MWLW_MASK (1LL << 31) +#define TEA5777_W_AM_MWLW_SHIFT 31 +#define TEA5777_W_AM_LNA_MASK (1LL << 30) +#define TEA5777_W_AM_LNA_SHIFT 30 + +#define TEA5777_W_AM_PEAK_MASK (1LL << 25) +#define TEA5777_W_AM_PEAK_SHIFT 25 + +#define TEA5777_W_AM_RFB_MASK (1LL << 16) +#define TEA5777_W_AM_RFB_SHIFT 16 +#define TEA5777_W_AM_CALLIGN_MASK (1LL << 15) +#define TEA5777_W_AM_CALLIGN_SHIFT 15 +#define TEA5777_W_AM_CBANK_MASK (0x7fLL << 8) +#define TEA5777_W_AM_CBANK_SHIFT 8 + +#define TEA5777_W_AM_DELAY_MASK (1LL << 2) +#define TEA5777_W_AM_DELAY_SHIFT 2 +#define TEA5777_W_AM_STEP_MASK (1LL << 1) +#define TEA5777_W_AM_STEP_SHIFT 1 + +/* Read reg, common bits */ +#define TEA5777_R_LEVEL_MASK (0x0f << 17) +#define TEA5777_R_LEVEL_SHIFT 17 +#define TEA5777_R_SFOUND_MASK (0x01 << 16) +#define TEA5777_R_SFOUND_SHIFT 16 +#define TEA5777_R_BLIM_MASK (0x01 << 15) +#define TEA5777_R_BLIM_SHIFT 15 + +/* Read reg, FM specific bits */ +#define TEA5777_R_FM_STEREO_MASK (0x01 << 21) +#define TEA5777_R_FM_STEREO_SHIFT 21 +#define TEA5777_R_FM_PLL_MASK 0x1fff +#define TEA5777_R_FM_PLL_SHIFT 0 + +static u32 tea5777_freq_to_v4l2_freq(struct radio_tea5777 *tea, u32 freq) +{ + return (freq * TEA5777_FM_FREQ_STEP + TEA5777_FM_IF) * 16; +} + +static int radio_tea5777_set_freq(struct radio_tea5777 *tea) +{ + u64 freq; + int res; + + freq = clamp_t(u32, tea->freq, + TEA5777_FM_RANGELOW, TEA5777_FM_RANGEHIGH) + 8; + do_div(freq, 16); /* to kHz */ + + freq -= TEA5777_FM_IF; + do_div(freq, TEA5777_FM_FREQ_STEP); + + tea->write_reg &= ~(TEA5777_W_FM_PLL_MASK | TEA5777_W_FM_FREF_MASK); + tea->write_reg |= freq << TEA5777_W_FM_PLL_SHIFT; + tea->write_reg |= TEA5777_W_FM_FREF_VALUE << TEA5777_W_FM_FREF_SHIFT; + + res = tea->ops->write_reg(tea, tea->write_reg); + if (res) + return res; + + tea->needs_write = false; + tea->read_reg = -1; + tea->freq = tea5777_freq_to_v4l2_freq(tea, freq); + + return 0; +} + +static int radio_tea5777_update_read_reg(struct radio_tea5777 *tea, int wait) +{ + int res; + + if (tea->read_reg != -1) + return 0; + + if (tea->write_before_read && tea->needs_write) { + res = radio_tea5777_set_freq(tea); + if (res) + return res; + } + + if (wait) { + if (schedule_timeout_interruptible(msecs_to_jiffies(wait))) + return -ERESTARTSYS; + } + + res = tea->ops->read_reg(tea, &tea->read_reg); + if (res) + return res; + + tea->needs_write = true; + return 0; +} + +/* + * Linux Video interface + */ + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *v) +{ + struct radio_tea5777 *tea = video_drvdata(file); + + strlcpy(v->driver, tea->v4l2_dev->name, sizeof(v->driver)); + strlcpy(v->card, tea->card, sizeof(v->card)); + strlcat(v->card, " TEA5777", sizeof(v->card)); + strlcpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct radio_tea5777 *tea = video_drvdata(file); + int res; + + if (v->index > 0) + return -EINVAL; + + res = radio_tea5777_update_read_reg(tea, 0); + if (res) + return res; + + memset(v, 0, sizeof(*v)); + if (tea->has_am) + strlcpy(v->name, "AM/FM", sizeof(v->name)); + else + strlcpy(v->name, "FM", sizeof(v->name)); + v->type = V4L2_TUNER_RADIO; + v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_HWSEEK_BOUNDED; + v->rangelow = TEA5777_FM_RANGELOW; + v->rangehigh = TEA5777_FM_RANGEHIGH; + v->rxsubchans = (tea->read_reg & TEA5777_R_FM_STEREO_MASK) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + v->audmode = (tea->write_reg & TEA5777_W_FM_FORCEMONO_MASK) ? + V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO; + /* shift - 12 to convert 4-bits (0-15) scale to 16-bits (0-65535) */ + v->signal = (tea->read_reg & TEA5777_R_LEVEL_MASK) >> + (TEA5777_R_LEVEL_SHIFT - 12); + + /* Invalidate read_reg, so that next call we return up2date signal */ + tea->read_reg = -1; + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *v) +{ + struct radio_tea5777 *tea = video_drvdata(file); + + if (v->index) + return -EINVAL; + + if (v->audmode == V4L2_TUNER_MODE_MONO) + tea->write_reg |= TEA5777_W_FM_FORCEMONO_MASK; + else + tea->write_reg &= ~TEA5777_W_FM_FORCEMONO_MASK; + + return radio_tea5777_set_freq(tea); +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct radio_tea5777 *tea = video_drvdata(file); + + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = tea->freq; + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct radio_tea5777 *tea = video_drvdata(file); + + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + tea->freq = f->frequency; + return radio_tea5777_set_freq(tea); +} + +static int vidioc_s_hw_freq_seek(struct file *file, void *fh, + struct v4l2_hw_freq_seek *a) +{ + struct radio_tea5777 *tea = video_drvdata(file); + u32 orig_freq = tea->freq; + unsigned long timeout; + int res, spacing = 200 * 16; /* 200 kHz */ + /* These are fixed *for now* */ + const u32 seek_rangelow = TEA5777_FM_RANGELOW; + const u32 seek_rangehigh = TEA5777_FM_RANGEHIGH; + + if (a->tuner || a->wrap_around) + return -EINVAL; + + tea->write_reg |= TEA5777_W_PROGBLIM_MASK; + if (seek_rangelow != tea->seek_rangelow) { + tea->write_reg &= ~TEA5777_W_UPDWN_MASK; + tea->freq = seek_rangelow; + res = radio_tea5777_set_freq(tea); + if (res) + goto leave; + tea->seek_rangelow = tea->freq; + } + if (seek_rangehigh != tea->seek_rangehigh) { + tea->write_reg |= TEA5777_W_UPDWN_MASK; + tea->freq = seek_rangehigh; + res = radio_tea5777_set_freq(tea); + if (res) + goto leave; + tea->seek_rangehigh = tea->freq; + } + tea->write_reg &= ~TEA5777_W_PROGBLIM_MASK; + + tea->write_reg |= TEA5777_W_SEARCH_MASK; + if (a->seek_upward) { + tea->write_reg |= TEA5777_W_UPDWN_MASK; + tea->freq = orig_freq + spacing; + } else { + tea->write_reg &= ~TEA5777_W_UPDWN_MASK; + tea->freq = orig_freq - spacing; + } + res = radio_tea5777_set_freq(tea); + if (res) + goto leave; + + timeout = jiffies + msecs_to_jiffies(5000); + for (;;) { + if (time_after(jiffies, timeout)) { + res = -ENODATA; + break; + } + + res = radio_tea5777_update_read_reg(tea, 100); + if (res) + break; + + /* + * Note we use tea->freq to track how far we've searched sofar + * this is necessary to ensure we continue seeking at the right + * point, in the write_before_read case. + */ + tea->freq = (tea->read_reg & TEA5777_R_FM_PLL_MASK); + tea->freq = tea5777_freq_to_v4l2_freq(tea, tea->freq); + + if ((tea->read_reg & TEA5777_R_SFOUND_MASK)) { + tea->write_reg &= ~TEA5777_W_SEARCH_MASK; + return 0; + } + + if (tea->read_reg & TEA5777_R_BLIM_MASK) { + res = -ENODATA; + break; + } + + /* Force read_reg update */ + tea->read_reg = -1; + } +leave: + tea->write_reg &= ~TEA5777_W_PROGBLIM_MASK; + tea->write_reg &= ~TEA5777_W_SEARCH_MASK; + tea->freq = orig_freq; + radio_tea5777_set_freq(tea); + return res; +} + +static int tea575x_s_ctrl(struct v4l2_ctrl *c) +{ + struct radio_tea5777 *tea = + container_of(c->handler, struct radio_tea5777, ctrl_handler); + + switch (c->id) { + case V4L2_CID_AUDIO_MUTE: + if (c->val) + tea->write_reg |= TEA5777_W_MUTE_MASK; + else + tea->write_reg &= ~TEA5777_W_MUTE_MASK; + + return radio_tea5777_set_freq(tea); + } + + return -EINVAL; +} + +static const struct v4l2_file_operations tea575x_fops = { + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = v4l2_fh_release, + .poll = v4l2_ctrl_poll, +}; + +static const struct v4l2_ioctl_ops tea575x_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct video_device tea575x_radio = { + .ioctl_ops = &tea575x_ioctl_ops, + .release = video_device_release_empty, +}; + +static const struct v4l2_ctrl_ops tea575x_ctrl_ops = { + .s_ctrl = tea575x_s_ctrl, +}; + +int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner) +{ + int res; + + tea->write_reg = (1LL << TEA5777_W_IFCE_SHIFT) | + (1LL << TEA5777_W_IFW_SHIFT) | + (1LL << TEA5777_W_INTEXT_SHIFT) | + (1LL << TEA5777_W_CHP0_SHIFT) | + (2LL << TEA5777_W_SLEV_SHIFT); + tea->freq = 90500 * 16; /* 90.5Mhz default */ + res = radio_tea5777_set_freq(tea); + if (res) { + v4l2_err(tea->v4l2_dev, "can't set initial freq (%d)\n", res); + return res; + } + + tea->vd = tea575x_radio; + video_set_drvdata(&tea->vd, tea); + mutex_init(&tea->mutex); + strlcpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); + tea->vd.lock = &tea->mutex; + tea->vd.v4l2_dev = tea->v4l2_dev; + tea->fops = tea575x_fops; + tea->fops.owner = owner; + tea->vd.fops = &tea->fops; + set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags); + + tea->vd.ctrl_handler = &tea->ctrl_handler; + v4l2_ctrl_handler_init(&tea->ctrl_handler, 1); + v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + res = tea->ctrl_handler.error; + if (res) { + v4l2_err(tea->v4l2_dev, "can't initialize controls\n"); + v4l2_ctrl_handler_free(&tea->ctrl_handler); + return res; + } + v4l2_ctrl_handler_setup(&tea->ctrl_handler); + + res = video_register_device(&tea->vd, VFL_TYPE_RADIO, -1); + if (res) { + v4l2_err(tea->v4l2_dev, "can't register video device!\n"); + v4l2_ctrl_handler_free(tea->vd.ctrl_handler); + return res; + } + + return 0; +} +EXPORT_SYMBOL_GPL(radio_tea5777_init); + +void radio_tea5777_exit(struct radio_tea5777 *tea) +{ + video_unregister_device(&tea->vd); + v4l2_ctrl_handler_free(tea->vd.ctrl_handler); +} +EXPORT_SYMBOL_GPL(radio_tea5777_exit); diff --git a/drivers/media/radio/radio-tea5777.h b/drivers/media/radio/radio-tea5777.h new file mode 100644 index 000000000000..55cbd78df5ed --- /dev/null +++ b/drivers/media/radio/radio-tea5777.h @@ -0,0 +1,87 @@ +#ifndef __RADIO_TEA5777_H +#define __RADIO_TEA5777_H + +/* + * v4l2 driver for TEA5777 Philips AM/FM radio tuner chips + * + * Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com> + * + * Based on the ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips: + * + * Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz> + * Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/videodev2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> + +#define TEA575X_FMIF 10700 +#define TEA575X_AMIF 450 + +struct radio_tea5777; + +struct radio_tea5777_ops { + /* + * Write the 6 bytes large write register of the tea5777 + * + * val represents the 6 write registers, with byte 1 from the + * datasheet being the most significant byte (so byte 5 of the u64), + * and byte 6 from the datasheet being the least significant byte. + * + * returns 0 on success. + */ + int (*write_reg)(struct radio_tea5777 *tea, u64 val); + /* + * Read the 3 bytes large read register of the tea5777 + * + * The read value gets returned in val, akin to write_reg, byte 1 from + * the datasheet is stored as the most significant byte (so byte 2 of + * the u32), and byte 3 from the datasheet gets stored as the least + * significant byte (iow byte 0 of the u32). + * + * returns 0 on success. + */ + int (*read_reg)(struct radio_tea5777 *tea, u32 *val); +}; + +struct radio_tea5777 { + struct v4l2_device *v4l2_dev; + struct v4l2_file_operations fops; + struct video_device vd; /* video device */ + bool has_am; /* Device can tune to AM freqs */ + bool write_before_read; /* must write before read quirk */ + bool needs_write; /* for write before read quirk */ + u32 freq; /* current frequency */ + u32 seek_rangelow; /* current hwseek limits */ + u32 seek_rangehigh; + u32 read_reg; + u64 write_reg; + struct mutex mutex; + struct radio_tea5777_ops *ops; + void *private_data; + u8 card[32]; + u8 bus_info[32]; + struct v4l2_ctrl_handler ctrl_handler; +}; + +int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner); +void radio_tea5777_exit(struct radio_tea5777 *tea); + +#endif /* __RADIO_TEA5777_H */ diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index f1b607099b6c..e8428f573ccd 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1514,7 +1514,8 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv, tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO; + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO | + V4L2_TUNER_CAP_HWSEEK_BOUNDED | V4L2_TUNER_CAP_HWSEEK_WRAP; if (radio->stereo) tuner->audmode = V4L2_TUNER_MODE_STEREO; diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 969cf494d85b..9e38132afec6 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -4,6 +4,7 @@ * Driver for radios with Silicon Labs Si470x FM Radio Receivers * * Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net> + * Copyright (c) 2012 Hans de Goede <hdegoede@redhat.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 @@ -127,14 +128,6 @@ static unsigned short space = 2; module_param(space, ushort, 0444); MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*"); -/* Bottom of Band (MHz) */ -/* 0: 87.5 - 108 MHz (USA, Europe)*/ -/* 1: 76 - 108 MHz (Japan wide band) */ -/* 2: 76 - 90 MHz (Japan) */ -static unsigned short band = 1; -module_param(band, ushort, 0444); -MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz"); - /* De-emphasis */ /* 0: 75 us (USA) */ /* 1: 50 us (Europe, Australia, Japan) */ @@ -152,19 +145,66 @@ static unsigned int seek_timeout = 5000; module_param(seek_timeout, uint, 0644); MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*"); - +static const struct v4l2_frequency_band bands[] = { + { + .type = V4L2_TUNER_RADIO, + .index = 0, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO | + V4L2_TUNER_CAP_HWSEEK_BOUNDED | + V4L2_TUNER_CAP_HWSEEK_WRAP, + .rangelow = 87500 * 16, + .rangehigh = 108000 * 16, + .modulation = V4L2_BAND_MODULATION_FM, + }, + { + .type = V4L2_TUNER_RADIO, + .index = 1, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO | + V4L2_TUNER_CAP_HWSEEK_BOUNDED | + V4L2_TUNER_CAP_HWSEEK_WRAP, + .rangelow = 76000 * 16, + .rangehigh = 108000 * 16, + .modulation = V4L2_BAND_MODULATION_FM, + }, + { + .type = V4L2_TUNER_RADIO, + .index = 2, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO | + V4L2_TUNER_CAP_HWSEEK_BOUNDED | + V4L2_TUNER_CAP_HWSEEK_WRAP, + .rangelow = 76000 * 16, + .rangehigh = 90000 * 16, + .modulation = V4L2_BAND_MODULATION_FM, + }, +}; /************************************************************************** * Generic Functions **************************************************************************/ /* + * si470x_set_band - set the band + */ +static int si470x_set_band(struct si470x_device *radio, int band) +{ + if (radio->band == band) + return 0; + + radio->band = band; + radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_BAND; + radio->registers[SYSCONFIG2] |= radio->band << 6; + return si470x_set_register(radio, SYSCONFIG2); +} + +/* * si470x_set_chan - set the channel */ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) { int retval; - unsigned long timeout; bool timed_out = 0; /* start tuning */ @@ -174,26 +214,12 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) if (retval < 0) goto done; - /* currently I2C driver only uses interrupt way to tune */ - if (radio->stci_enabled) { - INIT_COMPLETION(radio->completion); - - /* wait till tune operation has completed */ - retval = wait_for_completion_timeout(&radio->completion, - msecs_to_jiffies(tune_timeout)); - if (!retval) - timed_out = true; - } else { - /* wait till tune operation has completed */ - timeout = jiffies + msecs_to_jiffies(tune_timeout); - do { - retval = si470x_get_register(radio, STATUSRSSI); - if (retval < 0) - goto stop; - timed_out = time_after(jiffies, timeout); - } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) - && (!timed_out)); - } + /* wait till tune operation has completed */ + INIT_COMPLETION(radio->completion); + retval = wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(tune_timeout)); + if (!retval) + timed_out = true; if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) dev_warn(&radio->videodev.dev, "tune does not complete\n"); @@ -201,7 +227,6 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) dev_warn(&radio->videodev.dev, "tune timed out after %u ms\n", tune_timeout); -stop: /* stop tuning */ radio->registers[CHANNEL] &= ~CHANNEL_TUNE; retval = si470x_set_register(radio, CHANNEL); @@ -210,48 +235,39 @@ done: return retval; } - /* - * si470x_get_freq - get the frequency + * si470x_get_step - get channel spacing */ -static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) +static unsigned int si470x_get_step(struct si470x_device *radio) { - unsigned int spacing, band_bottom; - unsigned short chan; - int retval; - /* Spacing (kHz) */ switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { /* 0: 200 kHz (USA, Australia) */ case 0: - spacing = 0.200 * FREQ_MUL; break; + return 200 * 16; /* 1: 100 kHz (Europe, Japan) */ case 1: - spacing = 0.100 * FREQ_MUL; break; + return 100 * 16; /* 2: 50 kHz */ default: - spacing = 0.050 * FREQ_MUL; break; + return 50 * 16; }; +} - /* Bottom of Band (MHz) */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { - /* 0: 87.5 - 108 MHz (USA, Europe) */ - case 0: - band_bottom = 87.5 * FREQ_MUL; break; - /* 1: 76 - 108 MHz (Japan wide band) */ - default: - band_bottom = 76 * FREQ_MUL; break; - /* 2: 76 - 90 MHz (Japan) */ - case 2: - band_bottom = 76 * FREQ_MUL; break; - }; + +/* + * si470x_get_freq - get the frequency + */ +static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) +{ + int chan, retval; /* read channel */ retval = si470x_get_register(radio, READCHAN); chan = radio->registers[READCHAN] & READCHAN_READCHAN; /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ - *freq = chan * spacing + band_bottom; + *freq = chan * si470x_get_step(radio) + bands[radio->band].rangelow; return retval; } @@ -262,44 +278,12 @@ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) */ int si470x_set_freq(struct si470x_device *radio, unsigned int freq) { - unsigned int spacing, band_bottom, band_top; unsigned short chan; - /* Spacing (kHz) */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { - /* 0: 200 kHz (USA, Australia) */ - case 0: - spacing = 0.200 * FREQ_MUL; break; - /* 1: 100 kHz (Europe, Japan) */ - case 1: - spacing = 0.100 * FREQ_MUL; break; - /* 2: 50 kHz */ - default: - spacing = 0.050 * FREQ_MUL; break; - }; - - /* Bottom/Top of Band (MHz) */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { - /* 0: 87.5 - 108 MHz (USA, Europe) */ - case 0: - band_bottom = 87.5 * FREQ_MUL; - band_top = 108 * FREQ_MUL; - break; - /* 1: 76 - 108 MHz (Japan wide band) */ - default: - band_bottom = 76 * FREQ_MUL; - band_top = 108 * FREQ_MUL; - break; - /* 2: 76 - 90 MHz (Japan) */ - case 2: - band_bottom = 76 * FREQ_MUL; - band_top = 90 * FREQ_MUL; - break; - }; - - freq = clamp(freq, band_bottom, band_top); + freq = clamp(freq, bands[radio->band].rangelow, + bands[radio->band].rangehigh); /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ - chan = (freq - band_bottom) / spacing; + chan = (freq - bands[radio->band].rangelow) / si470x_get_step(radio); return si470x_set_chan(radio, chan); } @@ -309,19 +293,43 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq) * si470x_set_seek - set seek */ static int si470x_set_seek(struct si470x_device *radio, - unsigned int wrap_around, unsigned int seek_upward) + struct v4l2_hw_freq_seek *seek) { - int retval = 0; - unsigned long timeout; + int band, retval; + unsigned int freq; bool timed_out = 0; + /* set band */ + if (seek->rangelow || seek->rangehigh) { + for (band = 0; band < ARRAY_SIZE(bands); band++) { + if (bands[band].rangelow == seek->rangelow && + bands[band].rangehigh == seek->rangehigh) + break; + } + if (band == ARRAY_SIZE(bands)) + return -EINVAL; /* No matching band found */ + } else + band = 1; /* If nothing is specified seek 76 - 108 Mhz */ + + if (radio->band != band) { + retval = si470x_get_freq(radio, &freq); + if (retval) + return retval; + retval = si470x_set_band(radio, band); + if (retval) + return retval; + retval = si470x_set_freq(radio, freq); + if (retval) + return retval; + } + /* start seeking */ radio->registers[POWERCFG] |= POWERCFG_SEEK; - if (wrap_around == 1) + if (seek->wrap_around) radio->registers[POWERCFG] &= ~POWERCFG_SKMODE; else radio->registers[POWERCFG] |= POWERCFG_SKMODE; - if (seek_upward == 1) + if (seek->seek_upward) radio->registers[POWERCFG] |= POWERCFG_SEEKUP; else radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP; @@ -329,26 +337,12 @@ static int si470x_set_seek(struct si470x_device *radio, if (retval < 0) return retval; - /* currently I2C driver only uses interrupt way to seek */ - if (radio->stci_enabled) { - INIT_COMPLETION(radio->completion); - - /* wait till seek operation has completed */ - retval = wait_for_completion_timeout(&radio->completion, - msecs_to_jiffies(seek_timeout)); - if (!retval) - timed_out = true; - } else { - /* wait till seek operation has completed */ - timeout = jiffies + msecs_to_jiffies(seek_timeout); - do { - retval = si470x_get_register(radio, STATUSRSSI); - if (retval < 0) - goto stop; - timed_out = time_after(jiffies, timeout); - } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) - && (!timed_out)); - } + /* wait till tune operation has completed */ + INIT_COMPLETION(radio->completion); + retval = wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(seek_timeout)); + if (!retval) + timed_out = true; if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) dev_warn(&radio->videodev.dev, "seek does not complete\n"); @@ -356,14 +350,13 @@ static int si470x_set_seek(struct si470x_device *radio, dev_warn(&radio->videodev.dev, "seek failed / band limit reached\n"); -stop: /* stop seeking */ radio->registers[POWERCFG] &= ~POWERCFG_SEEK; retval = si470x_set_register(radio, POWERCFG); /* try again, if timed out */ if (retval == 0 && timed_out) - return -EAGAIN; + return -ENODATA; return retval; } @@ -391,8 +384,8 @@ int si470x_start(struct si470x_device *radio) /* sysconfig 2 */ radio->registers[SYSCONFIG2] = - (0x3f << 8) | /* SEEKTH */ - ((band << 6) & SYSCONFIG2_BAND) | /* BAND */ + (0x1f << 8) | /* SEEKTH */ + ((radio->band << 6) & SYSCONFIG2_BAND) |/* BAND */ ((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */ 15; /* VOLUME (max) */ retval = si470x_set_register(radio, SYSCONFIG2); @@ -583,39 +576,26 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { struct si470x_device *radio = video_drvdata(file); - int retval; + int retval = 0; if (tuner->index != 0) return -EINVAL; - retval = si470x_get_register(radio, STATUSRSSI); - if (retval < 0) - return retval; + if (!radio->status_rssi_auto_update) { + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + return retval; + } /* driver constants */ strcpy(tuner->name, "FM"); tuner->type = V4L2_TUNER_RADIO; tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; - - /* range limits */ - switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { - /* 0: 87.5 - 108 MHz (USA, Europe, default) */ - default: - tuner->rangelow = 87.5 * FREQ_MUL; - tuner->rangehigh = 108 * FREQ_MUL; - break; - /* 1: 76 - 108 MHz (Japan wide band) */ - case 1: - tuner->rangelow = 76 * FREQ_MUL; - tuner->rangehigh = 108 * FREQ_MUL; - break; - /* 2: 76 - 90 MHz (Japan) */ - case 2: - tuner->rangelow = 76 * FREQ_MUL; - tuner->rangehigh = 90 * FREQ_MUL; - break; - }; + V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO | + V4L2_TUNER_CAP_HWSEEK_BOUNDED | + V4L2_TUNER_CAP_HWSEEK_WRAP; + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; /* stereo indicator == stereo (instead of mono) */ if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) @@ -698,10 +678,18 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { struct si470x_device *radio = video_drvdata(file); + int retval; if (freq->tuner != 0) return -EINVAL; + if (freq->frequency < bands[radio->band].rangelow || + freq->frequency > bands[radio->band].rangehigh) { + /* Switch to band 1 which covers everything we support */ + retval = si470x_set_band(radio, 1); + if (retval) + return retval; + } return si470x_set_freq(radio, freq->frequency); } @@ -717,7 +705,21 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, if (seek->tuner != 0) return -EINVAL; - return si470x_set_seek(radio, seek->wrap_around, seek->seek_upward); + return si470x_set_seek(radio, seek); +} + +/* + * si470x_vidioc_enum_freq_bands - enumerate supported bands + */ +static int si470x_vidioc_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + if (band->tuner != 0) + return -EINVAL; + if (band->index >= ARRAY_SIZE(bands)) + return -EINVAL; + *band = bands[band->index]; + return 0; } const struct v4l2_ctrl_ops si470x_ctrl_ops = { @@ -734,6 +736,7 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = { .vidioc_g_frequency = si470x_vidioc_g_frequency, .vidioc_s_frequency = si470x_vidioc_s_frequency, .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, + .vidioc_enum_freq_bands = si470x_vidioc_enum_freq_bands, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index a80044c5874e..643a6ff7c5d0 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -350,7 +350,9 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, } radio->client = client; + radio->band = 1; /* Default to 76 - 108 MHz */ mutex_init(&radio->lock); + init_completion(&radio->completion); /* video device initialization */ radio->videodev = si470x_viddev_template; @@ -406,10 +408,6 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, radio->rd_index = 0; init_waitqueue_head(&radio->read_queue); - /* mark Seek/Tune Complete Interrupt enabled */ - radio->stci_enabled = true; - init_completion(&radio->completion); - retval = request_threaded_irq(client->irq, NULL, si470x_i2c_interrupt, IRQF_TRIGGER_FALLING, DRIVER_NAME, radio); if (retval) { diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index f412f7ab270b..146be4263ea1 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -143,7 +143,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); * Software/Hardware Versions from Scratch Page **************************************************************************/ #define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6 -#define RADIO_SW_VERSION 7 +#define RADIO_SW_VERSION 1 #define RADIO_HW_VERSION 1 @@ -399,12 +399,19 @@ static void si470x_int_in_callback(struct urb *urb) } } - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + /* Sometimes the device returns len 0 packets */ + if (urb->actual_length != RDS_REPORT_SIZE) goto resubmit; - if (urb->actual_length > 0) { + radio->registers[STATUSRSSI] = + get_unaligned_be16(&radio->int_in_buffer[1]); + + if (radio->registers[STATUSRSSI] & STATUSRSSI_STC) + complete(&radio->completion); + + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS)) { /* Update RDS registers with URB data */ - for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) + for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) radio->registers[STATUSRSSI + regnr] = get_unaligned_be16(&radio->int_in_buffer[ regnr * RADIO_REGISTER_SIZE + 1]); @@ -480,6 +487,7 @@ resubmit: radio->int_in_running = 0; } } + radio->status_rssi_auto_update = radio->int_in_running; } @@ -534,13 +542,6 @@ static int si470x_start_usb(struct si470x_device *radio) { int retval; - /* start radio */ - retval = si470x_start(radio); - if (retval < 0) - return retval; - - v4l2_ctrl_handler_setup(&radio->hdl); - /* initialize interrupt urb */ usb_fill_int_urb(radio->int_in_urb, radio->usbdev, usb_rcvintpipe(radio->usbdev, @@ -560,6 +561,15 @@ static int si470x_start_usb(struct si470x_device *radio) "submitting int urb failed (%d)\n", retval); radio->int_in_running = 0; } + radio->status_rssi_auto_update = radio->int_in_running; + + /* start radio */ + retval = si470x_start(radio); + if (retval < 0) + return retval; + + v4l2_ctrl_handler_setup(&radio->hdl); + return retval; } @@ -587,7 +597,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, } radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; + radio->band = 1; /* Default to 76 - 108 MHz */ mutex_init(&radio->lock); + init_completion(&radio->completion); iface_desc = intf->cur_altsetting; @@ -698,9 +710,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, "linux-media@vger.kernel.org\n"); } - /* set initial frequency */ - si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ - /* set led to connect state */ si470x_set_led_state(radio, BLINK_GREEN_LED); @@ -723,6 +732,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, if (retval < 0) goto err_all; + /* set initial frequency */ + si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ + /* register video device */ retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); @@ -781,11 +793,16 @@ static int si470x_usb_driver_suspend(struct usb_interface *intf, static int si470x_usb_driver_resume(struct usb_interface *intf) { struct si470x_device *radio = usb_get_intfdata(intf); + int ret; dev_info(&intf->dev, "resuming now...\n"); /* start radio */ - return si470x_start_usb(radio); + ret = si470x_start_usb(radio); + if (ret == 0) + v4l2_ctrl_handler_setup(&radio->hdl); + + return ret; } diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index 4921cab8e0fa..2f089b4252df 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h @@ -87,7 +87,7 @@ #define SYSCONFIG2 5 /* System Configuration 2 */ #define SYSCONFIG2_SEEKTH 0xff00 /* bits 15..08: RSSI Seek Threshold */ -#define SYSCONFIG2_BAND 0x0080 /* bits 07..06: Band Select */ +#define SYSCONFIG2_BAND 0x00c0 /* bits 07..06: Band Select */ #define SYSCONFIG2_SPACE 0x0030 /* bits 05..04: Channel Spacing */ #define SYSCONFIG2_VOLUME 0x000f /* bits 03..00: Volume */ @@ -147,6 +147,7 @@ struct si470x_device { struct v4l2_device v4l2_dev; struct video_device videodev; struct v4l2_ctrl_handler hdl; + int band; /* Silabs internal registers (0..15) */ unsigned short registers[RADIO_REGISTER_NUM]; @@ -160,7 +161,7 @@ struct si470x_device { unsigned int wr_index; struct completion completion; - bool stci_enabled; /* Seek/Tune Complete Interrupt */ + bool status_rssi_auto_update; /* Does RSSI get updated automatic? */ #if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) /* reference to USB and video device */ @@ -189,7 +190,7 @@ struct si470x_device { * Firmware Versions **************************************************************************/ -#define RADIO_FW_VERSION 15 +#define RADIO_FW_VERSION 12 diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c index 43fb72291bea..3dd9fc097c47 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.c +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -251,7 +251,7 @@ again: if (!timeleft) { fmerr("Timeout(%d sec),didn't get tune ended int\n", jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000); - return -ETIMEDOUT; + return -ENODATA; } int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT); diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 080b96a61f1a..49a11ec1f449 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -285,7 +285,9 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO | ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0); tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_LOW; + V4L2_TUNER_CAP_LOW | + V4L2_TUNER_CAP_HWSEEK_BOUNDED | + V4L2_TUNER_CAP_HWSEEK_WRAP; tuner->audmode = (stereo_mono_mode ? V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO); diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index f97eeb870455..5180390be7ab 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -1,21 +1,20 @@ -menuconfig RC_CORE - tristate "Remote Controller adapters" +config RC_CORE + tristate + depends on MEDIA_RC_SUPPORT depends on INPUT - default INPUT - ---help--- - Enable support for Remote Controllers on Linux. This is - needed in order to support several video capture adapters, - standalone IR receivers/transmitters, and RF receivers. + default y - Enable this option if you have a video capture board even - if you don't need IR, as otherwise, you may not be able to - compile the driver for your adapter. +source "drivers/media/rc/keymaps/Kconfig" -if RC_CORE +menuconfig RC_DECODERS + bool "Remote controller decoders" + depends on RC_CORE + default y +if RC_DECODERS config LIRC - tristate - default y + tristate "LIRC interface driver" + depends on RC_CORE ---help--- Enable this option to build the Linux Infrared Remote @@ -24,7 +23,16 @@ config LIRC LIRC daemon handles protocol decoding for IR reception and encoding for IR transmitting (aka "blasting"). -source "drivers/media/rc/keymaps/Kconfig" +config IR_LIRC_CODEC + tristate "Enable IR to LIRC bridge" + depends on RC_CORE + depends on LIRC + default y + + ---help--- + Enable this option to pass raw IR to and from userspace via + the LIRC interface. + config IR_NEC_DECODER tristate "Enable IR raw decoder for the NEC protocol" @@ -108,16 +116,13 @@ config IR_MCE_KBD_DECODER Enable this option if you have a Microsoft Remote Keyboard for Windows Media Center Edition, which you would like to use with a raw IR receiver in your system. +endif #RC_DECODERS -config IR_LIRC_CODEC - tristate "Enable IR to LIRC bridge" +menuconfig RC_DEVICES + bool "Remote Controller devices" depends on RC_CORE - depends on LIRC - default y - ---help--- - Enable this option to pass raw IR to and from userspace via - the LIRC interface. +if RC_DEVICES config RC_ATI_REMOTE tristate "ATI / X10 based USB RF remote controls" @@ -254,6 +259,17 @@ config IR_WINBOND_CIR To compile this driver as a module, choose M here: the module will be called winbond_cir. +config IR_IGUANA + tristate "IguanaWorks USB IR Transceiver" + depends on RC_CORE + select USB + ---help--- + Say Y here if you want to use the IgaunaWorks USB IR Transceiver. + Both infrared receive and send are supported. + + To compile this driver as a module, choose M here: the module will + be called iguanair. + config RC_LOOPBACK tristate "Remote Control Loopback Driver" depends on RC_CORE @@ -276,4 +292,4 @@ config IR_GPIO_CIR To compile this driver as a module, choose M here: the module will be called gpio-ir-recv. -endif #RC_CORE +endif #RC_DEVICES diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 29f364f88a94..f871d1986c21 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_IR_STREAMZAP) += streamzap.o obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o +obj-$(CONFIG_IR_IGUANA) += iguanair.o diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 7be377fc1be8..8fa72e2dacb1 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -147,7 +147,8 @@ static bool mouse = true; module_param(mouse, bool, 0444); MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes"); -#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) +#define dbginfo(dev, format, arg...) \ + do { if (debug) dev_info(dev , format , ## arg); } while (0) #undef err #define err(format, arg...) printk(KERN_ERR format , ## arg) @@ -191,17 +192,41 @@ static const char *get_medion_keymap(struct usb_interface *interface) return RC_MAP_MEDION_X10; } -static const struct ati_receiver_type type_ati = { .default_keymap = RC_MAP_ATI_X10 }; -static const struct ati_receiver_type type_medion = { .get_default_keymap = get_medion_keymap }; -static const struct ati_receiver_type type_firefly = { .default_keymap = RC_MAP_SNAPSTREAM_FIREFLY }; +static const struct ati_receiver_type type_ati = { + .default_keymap = RC_MAP_ATI_X10 +}; +static const struct ati_receiver_type type_medion = { + .get_default_keymap = get_medion_keymap +}; +static const struct ati_receiver_type type_firefly = { + .default_keymap = RC_MAP_SNAPSTREAM_FIREFLY +}; static struct usb_device_id ati_remote_table[] = { - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_medion }, - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_firefly }, + { + USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID), + .driver_info = (unsigned long)&type_ati + }, + { + USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID), + .driver_info = (unsigned long)&type_ati + }, + { + USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID), + .driver_info = (unsigned long)&type_ati + }, + { + USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID), + .driver_info = (unsigned long)&type_ati + }, + { + USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID), + .driver_info = (unsigned long)&type_medion + }, + { + USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID), + .driver_info = (unsigned long)&type_firefly + }, {} /* Terminating entry */ }; @@ -296,25 +321,8 @@ static const struct { {KIND_END, 0x00, EV_MAX + 1, 0, 0} }; -/* Local function prototypes */ -static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); -static void ati_remote_irq_out (struct urb *urb); -static void ati_remote_irq_in (struct urb *urb); -static void ati_remote_input_report (struct urb *urb); -static int ati_remote_initialize (struct ati_remote *ati_remote); -static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); -static void ati_remote_disconnect (struct usb_interface *interface); - -/* usb specific object to register with the usb subsystem */ -static struct usb_driver ati_remote_driver = { - .name = "ati_remote", - .probe = ati_remote_probe, - .disconnect = ati_remote_disconnect, - .id_table = ati_remote_table, -}; - /* - * ati_remote_dump_input + * ati_remote_dump_input */ static void ati_remote_dump(struct device *dev, unsigned char *data, unsigned int len) @@ -326,12 +334,14 @@ static void ati_remote_dump(struct device *dev, unsigned char *data, dev_warn(dev, "Weird key %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3]); else - dev_warn(dev, "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", - len, data[0], data[1], data[2], data[3], data[4], data[5]); + dev_warn(dev, + "Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", + len, data[0], data[1], data[2], data[3], data[4], + data[5]); } /* - * ati_remote_open + * ati_remote_open */ static int ati_remote_open(struct ati_remote *ati_remote) { @@ -355,7 +365,7 @@ out: mutex_unlock(&ati_remote->open_mutex); } /* - * ati_remote_close + * ati_remote_close */ static void ati_remote_close(struct ati_remote *ati_remote) { @@ -390,7 +400,7 @@ static void ati_remote_rc_close(struct rc_dev *rdev) } /* - * ati_remote_irq_out + * ati_remote_irq_out */ static void ati_remote_irq_out(struct urb *urb) { @@ -408,11 +418,12 @@ static void ati_remote_irq_out(struct urb *urb) } /* - * ati_remote_sendpacket + * ati_remote_sendpacket * - * Used to send device initialization strings + * Used to send device initialization strings */ -static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) +static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, + unsigned char *data) { int retval = 0; @@ -441,7 +452,7 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne } /* - * ati_remote_compute_accel + * ati_remote_compute_accel * * Implements acceleration curve for directional control pad * If elapsed time since last event is > 1/4 second, user "stopped", @@ -478,7 +489,7 @@ static int ati_remote_compute_accel(struct ati_remote *ati_remote) } /* - * ati_remote_report_input + * ati_remote_report_input */ static void ati_remote_input_report(struct urb *urb) { @@ -518,7 +529,8 @@ static void ati_remote_input_report(struct urb *urb) remote_num = (data[3] >> 4) & 0x0f; if (channel_mask & (1 << (remote_num + 1))) { dbginfo(&ati_remote->interface->dev, - "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", + "Masked input from channel 0x%02x: data %02x,%02x, " + "mask= 0x%02lx\n", remote_num, data[1], data[2], channel_mask); return; } @@ -546,7 +558,9 @@ static void ati_remote_input_report(struct urb *urb) if (wheel_keycode == KEY_RESERVED) { /* scrollwheel was not mapped, assume mouse */ - /* Look up event code index in the mouse translation table. */ + /* Look up event code index in the mouse translation + * table. + */ for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { if (scancode == ati_remote_tbl[i].data) { index = i; @@ -630,9 +644,9 @@ static void ati_remote_input_report(struct urb *urb) } else { /* - * Other event kinds are from the directional control pad, and have an - * acceleration factor applied to them. Without this acceleration, the - * control pad is mostly unusable. + * Other event kinds are from the directional control pad, and + * have an acceleration factor applied to them. Without this + * acceleration, the control pad is mostly unusable. */ acc = ati_remote_compute_accel(ati_remote); @@ -659,7 +673,8 @@ static void ati_remote_input_report(struct urb *urb) input_report_rel(dev, REL_Y, acc); break; default: - dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", + dev_dbg(&ati_remote->interface->dev, + "ati_remote kind=%d\n", ati_remote_tbl[index].kind); } input_sync(dev); @@ -670,7 +685,7 @@ static void ati_remote_input_report(struct urb *urb) } /* - * ati_remote_irq_in + * ati_remote_irq_in */ static void ati_remote_irq_in(struct urb *urb) { @@ -684,22 +699,25 @@ static void ati_remote_irq_in(struct urb *urb) case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: - dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", + dev_dbg(&ati_remote->interface->dev, + "%s: urb error status, unlink?\n", __func__); return; default: /* error */ - dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", + dev_dbg(&ati_remote->interface->dev, + "%s: Nonzero urb status %d\n", __func__, urb->status); } retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) - dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", + dev_err(&ati_remote->interface->dev, + "%s: usb_submit_urb()=%d\n", __func__, retval); } /* - * ati_remote_alloc_buffers + * ati_remote_alloc_buffers */ static int ati_remote_alloc_buffers(struct usb_device *udev, struct ati_remote *ati_remote) @@ -726,7 +744,7 @@ static int ati_remote_alloc_buffers(struct usb_device *udev, } /* - * ati_remote_free_buffers + * ati_remote_free_buffers */ static void ati_remote_free_buffers(struct ati_remote *ati_remote) { @@ -825,9 +843,10 @@ static int ati_remote_initialize(struct ati_remote *ati_remote) } /* - * ati_remote_probe + * ati_remote_probe */ -static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) +static int ati_remote_probe(struct usb_interface *interface, + const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); struct usb_host_interface *iface_host = interface->cur_altsetting; @@ -949,7 +968,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de } /* - * ati_remote_disconnect + * ati_remote_disconnect */ static void ati_remote_disconnect(struct usb_interface *interface) { @@ -971,6 +990,14 @@ static void ati_remote_disconnect(struct usb_interface *interface) kfree(ati_remote); } +/* usb specific object to register with the usb subsystem */ +static struct usb_driver ati_remote_driver = { + .name = "ati_remote", + .probe = ati_remote_probe, + .disconnect = ati_remote_disconnect, + .id_table = ati_remote_table, +}; + module_usb_driver(ati_remote_driver); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index bef5296173c9..647dd951b0e8 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1018,6 +1018,8 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) spin_lock_init(&dev->hw_lock); + dev->hw_io = pnp_port_start(pnp_dev, 0); + pnp_set_drvdata(pnp_dev, dev); dev->pnp_dev = pnp_dev; @@ -1072,7 +1074,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) /* claim the resources */ error = -EBUSY; - dev->hw_io = pnp_port_start(pnp_dev, 0); if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { dev->hw_io = -1; dev->irq = -1; diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 6aabf7ae3a31..ab30c64f8124 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -23,6 +23,8 @@ * USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/pnp.h> @@ -110,30 +112,32 @@ static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset) return val; } -#define pr_reg(text, ...) \ - printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__) - /* dump current cir register contents */ static void cir_dump_regs(struct fintek_dev *fintek) { fintek_config_mode_enable(fintek); fintek_select_logical_dev(fintek, fintek->logical_dev_cir); - pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME); - pr_reg(" * CR CIR BASE ADDR: 0x%x\n", - (fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) | + pr_info("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME); + pr_info(" * CR CIR BASE ADDR: 0x%x\n", + (fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) | fintek_cr_read(fintek, CIR_CR_BASE_ADDR_LO)); - pr_reg(" * CR CIR IRQ NUM: 0x%x\n", - fintek_cr_read(fintek, CIR_CR_IRQ_SEL)); + pr_info(" * CR CIR IRQ NUM: 0x%x\n", + fintek_cr_read(fintek, CIR_CR_IRQ_SEL)); fintek_config_mode_disable(fintek); - pr_reg("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME); - pr_reg(" * STATUS: 0x%x\n", fintek_cir_reg_read(fintek, CIR_STATUS)); - pr_reg(" * CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_CONTROL)); - pr_reg(" * RX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_RX_DATA)); - pr_reg(" * TX_CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_CONTROL)); - pr_reg(" * TX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_DATA)); + pr_info("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME); + pr_info(" * STATUS: 0x%x\n", + fintek_cir_reg_read(fintek, CIR_STATUS)); + pr_info(" * CONTROL: 0x%x\n", + fintek_cir_reg_read(fintek, CIR_CONTROL)); + pr_info(" * RX_DATA: 0x%x\n", + fintek_cir_reg_read(fintek, CIR_RX_DATA)); + pr_info(" * TX_CONTROL: 0x%x\n", + fintek_cir_reg_read(fintek, CIR_TX_CONTROL)); + pr_info(" * TX_DATA: 0x%x\n", + fintek_cir_reg_read(fintek, CIR_TX_DATA)); } /* detect hardware features */ diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 0d875450c5ce..04cb272db16a 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -82,12 +82,21 @@ static int __devinit gpio_ir_recv_probe(struct platform_device *pdev) goto err_allocate_device; } + rcdev->priv = gpio_dev; rcdev->driver_type = RC_DRIVER_IR_RAW; - rcdev->allowed_protos = RC_TYPE_ALL; rcdev->input_name = GPIO_IR_DEVICE_NAME; + rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0"; rcdev->input_id.bustype = BUS_HOST; + rcdev->input_id.vendor = 0x0001; + rcdev->input_id.product = 0x0001; + rcdev->input_id.version = 0x0100; + rcdev->dev.parent = &pdev->dev; rcdev->driver_name = GPIO_IR_DRIVER_NAME; - rcdev->map_name = RC_MAP_EMPTY; + if (pdata->allowed_protos) + rcdev->allowed_protos = pdata->allowed_protos; + else + rcdev->allowed_protos = RC_TYPE_ALL; + rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY; gpio_dev->rcdev = rcdev; gpio_dev->gpio_nr = pdata->gpio_nr; @@ -188,18 +197,7 @@ static struct platform_driver gpio_ir_recv_driver = { #endif }, }; - -static int __init gpio_ir_recv_init(void) -{ - return platform_driver_register(&gpio_ir_recv_driver); -} -module_init(gpio_ir_recv_init); - -static void __exit gpio_ir_recv_exit(void) -{ - platform_driver_unregister(&gpio_ir_recv_driver); -} -module_exit(gpio_ir_recv_exit); +module_platform_driver(gpio_ir_recv_driver); MODULE_DESCRIPTION("GPIO IR Receiver driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c new file mode 100644 index 000000000000..5e2eaf8ba73e --- /dev/null +++ b/drivers/media/rc/iguanair.c @@ -0,0 +1,639 @@ +/* + * IguanaWorks USB IR Transceiver support + * + * Copyright (C) 2012 Sean Young <sean@mess.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/input.h> +#include <linux/slab.h> +#include <linux/completion.h> +#include <media/rc-core.h> + +#define DRIVER_NAME "iguanair" + +struct iguanair { + struct rc_dev *rc; + + struct device *dev; + struct usb_device *udev; + + int pipe_in, pipe_out; + uint8_t bufsize; + uint8_t version[2]; + + struct mutex lock; + + /* receiver support */ + bool receiver_on; + dma_addr_t dma_in; + uint8_t *buf_in; + struct urb *urb_in; + struct completion completion; + + /* transmit support */ + bool tx_overflow; + uint32_t carrier; + uint8_t cycle_overhead; + uint8_t channels; + uint8_t busy4; + uint8_t busy7; + + char name[64]; + char phys[64]; +}; + +#define CMD_GET_VERSION 0x01 +#define CMD_GET_BUFSIZE 0x11 +#define CMD_GET_FEATURES 0x10 +#define CMD_SEND 0x15 +#define CMD_EXECUTE 0x1f +#define CMD_RX_OVERFLOW 0x31 +#define CMD_TX_OVERFLOW 0x32 +#define CMD_RECEIVER_ON 0x12 +#define CMD_RECEIVER_OFF 0x14 + +#define DIR_IN 0xdc +#define DIR_OUT 0xcd + +#define MAX_PACKET_SIZE 8u +#define TIMEOUT 1000 + +struct packet { + uint16_t start; + uint8_t direction; + uint8_t cmd; +}; + +struct response_packet { + struct packet header; + uint8_t data[4]; +}; + +struct send_packet { + struct packet header; + uint8_t length; + uint8_t channels; + uint8_t busy7; + uint8_t busy4; + uint8_t payload[0]; +}; + +static void process_ir_data(struct iguanair *ir, unsigned len) +{ + if (len >= 4 && ir->buf_in[0] == 0 && ir->buf_in[1] == 0) { + switch (ir->buf_in[3]) { + case CMD_TX_OVERFLOW: + ir->tx_overflow = true; + case CMD_RECEIVER_OFF: + case CMD_RECEIVER_ON: + case CMD_SEND: + complete(&ir->completion); + break; + case CMD_RX_OVERFLOW: + dev_warn(ir->dev, "receive overflow\n"); + break; + default: + dev_warn(ir->dev, "control code %02x received\n", + ir->buf_in[3]); + break; + } + } else if (len >= 7) { + DEFINE_IR_RAW_EVENT(rawir); + unsigned i; + + init_ir_raw_event(&rawir); + + for (i = 0; i < 7; i++) { + if (ir->buf_in[i] == 0x80) { + rawir.pulse = false; + rawir.duration = US_TO_NS(21845); + } else { + rawir.pulse = (ir->buf_in[i] & 0x80) == 0; + rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) * + 21330; + } + + ir_raw_event_store_with_filter(ir->rc, &rawir); + } + + ir_raw_event_handle(ir->rc); + } +} + +static void iguanair_rx(struct urb *urb) +{ + struct iguanair *ir; + + if (!urb) + return; + + ir = urb->context; + if (!ir) { + usb_unlink_urb(urb); + return; + } + + switch (urb->status) { + case 0: + process_ir_data(ir, urb->actual_length); + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + usb_unlink_urb(urb); + return; + case -EPIPE: + default: + dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); + break; + } + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int iguanair_send(struct iguanair *ir, void *data, unsigned size, + struct response_packet *response, unsigned *res_len) +{ + unsigned offset, len; + int rc, transferred; + + for (offset = 0; offset < size; offset += MAX_PACKET_SIZE) { + len = min(size - offset, MAX_PACKET_SIZE); + + if (ir->tx_overflow) + return -EOVERFLOW; + + rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data + offset, + len, &transferred, TIMEOUT); + if (rc) + return rc; + + if (transferred != len) + return -EIO; + } + + if (response) { + rc = usb_interrupt_msg(ir->udev, ir->pipe_in, response, + sizeof(*response), res_len, TIMEOUT); + } + + return rc; +} + +static int iguanair_get_features(struct iguanair *ir) +{ + struct packet packet; + struct response_packet response; + int rc, len; + + packet.start = 0; + packet.direction = DIR_OUT; + packet.cmd = CMD_GET_VERSION; + + rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len); + if (rc) { + dev_info(ir->dev, "failed to get version\n"); + goto out; + } + + if (len != 6) { + dev_info(ir->dev, "failed to get version\n"); + rc = -EIO; + goto out; + } + + ir->version[0] = response.data[0]; + ir->version[1] = response.data[1]; + ir->bufsize = 150; + ir->cycle_overhead = 65; + + packet.cmd = CMD_GET_BUFSIZE; + + rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len); + if (rc) { + dev_info(ir->dev, "failed to get buffer size\n"); + goto out; + } + + if (len != 5) { + dev_info(ir->dev, "failed to get buffer size\n"); + rc = -EIO; + goto out; + } + + ir->bufsize = response.data[0]; + + if (ir->version[0] == 0 || ir->version[1] == 0) + goto out; + + packet.cmd = CMD_GET_FEATURES; + + rc = iguanair_send(ir, &packet, sizeof(packet), &response, &len); + if (rc) { + dev_info(ir->dev, "failed to get features\n"); + goto out; + } + + if (len < 5) { + dev_info(ir->dev, "failed to get features\n"); + rc = -EIO; + goto out; + } + + if (len > 5 && ir->version[0] >= 4) + ir->cycle_overhead = response.data[1]; + +out: + return rc; +} + +static int iguanair_receiver(struct iguanair *ir, bool enable) +{ + struct packet packet = { 0, DIR_OUT, enable ? + CMD_RECEIVER_ON : CMD_RECEIVER_OFF }; + int rc; + + INIT_COMPLETION(ir->completion); + + rc = iguanair_send(ir, &packet, sizeof(packet), NULL, NULL); + if (rc) + return rc; + + wait_for_completion_timeout(&ir->completion, TIMEOUT); + + return 0; +} + +/* + * The iguana ir creates the carrier by busy spinning after each pulse or + * space. This is counted in CPU cycles, with the CPU running at 24MHz. It is + * broken down into 7-cycles and 4-cyles delays, with a preference for + * 4-cycle delays. + */ +static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier) +{ + struct iguanair *ir = dev->priv; + + if (carrier < 25000 || carrier > 150000) + return -EINVAL; + + mutex_lock(&ir->lock); + + if (carrier != ir->carrier) { + uint32_t cycles, fours, sevens; + + ir->carrier = carrier; + + cycles = DIV_ROUND_CLOSEST(24000000, carrier * 2) - + ir->cycle_overhead; + + /* make up the the remainer of 4-cycle blocks */ + switch (cycles & 3) { + case 0: + sevens = 0; + break; + case 1: + sevens = 3; + break; + case 2: + sevens = 2; + break; + case 3: + sevens = 1; + break; + } + + fours = (cycles - sevens * 7) / 4; + + /* magic happens here */ + ir->busy7 = (4 - sevens) * 2; + ir->busy4 = 110 - fours; + } + + mutex_unlock(&ir->lock); + + return carrier; +} + +static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask) +{ + struct iguanair *ir = dev->priv; + + if (mask > 15) + return 4; + + mutex_lock(&ir->lock); + ir->channels = mask; + mutex_unlock(&ir->lock); + + return 0; +} + +static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) +{ + struct iguanair *ir = dev->priv; + uint8_t space, *payload; + unsigned i, size, rc; + struct send_packet *packet; + + mutex_lock(&ir->lock); + + /* convert from us to carrier periods */ + for (i = size = 0; i < count; i++) { + txbuf[i] = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); + size += (txbuf[i] + 126) / 127; + } + + packet = kmalloc(sizeof(*packet) + size, GFP_KERNEL); + if (!packet) { + rc = -ENOMEM; + goto out; + } + + if (size > ir->bufsize) { + rc = -E2BIG; + goto out; + } + + packet->header.start = 0; + packet->header.direction = DIR_OUT; + packet->header.cmd = CMD_SEND; + packet->length = size; + packet->channels = ir->channels << 4; + packet->busy7 = ir->busy7; + packet->busy4 = ir->busy4; + + space = 0; + payload = packet->payload; + + for (i = 0; i < count; i++) { + unsigned periods = txbuf[i]; + + while (periods > 127) { + *payload++ = 127 | space; + periods -= 127; + } + + *payload++ = periods | space; + space ^= 0x80; + } + + if (ir->receiver_on) { + rc = iguanair_receiver(ir, false); + if (rc) { + dev_warn(ir->dev, "disable receiver before transmit failed\n"); + goto out; + } + } + + ir->tx_overflow = false; + + INIT_COMPLETION(ir->completion); + + rc = iguanair_send(ir, packet, size + 8, NULL, NULL); + + if (rc == 0) { + wait_for_completion_timeout(&ir->completion, TIMEOUT); + if (ir->tx_overflow) + rc = -EOVERFLOW; + } + + ir->tx_overflow = false; + + if (ir->receiver_on) { + if (iguanair_receiver(ir, true)) + dev_warn(ir->dev, "re-enable receiver after transmit failed\n"); + } + +out: + mutex_unlock(&ir->lock); + kfree(packet); + + return rc; +} + +static int iguanair_open(struct rc_dev *rdev) +{ + struct iguanair *ir = rdev->priv; + int rc; + + mutex_lock(&ir->lock); + + usb_submit_urb(ir->urb_in, GFP_KERNEL); + + BUG_ON(ir->receiver_on); + + rc = iguanair_receiver(ir, true); + if (rc == 0) + ir->receiver_on = true; + + mutex_unlock(&ir->lock); + + return rc; +} + +static void iguanair_close(struct rc_dev *rdev) +{ + struct iguanair *ir = rdev->priv; + int rc; + + mutex_lock(&ir->lock); + + rc = iguanair_receiver(ir, false); + ir->receiver_on = false; + if (rc) + dev_warn(ir->dev, "failed to disable receiver: %d\n", rc); + + usb_kill_urb(ir->urb_in); + + mutex_unlock(&ir->lock); +} + +static int __devinit iguanair_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct iguanair *ir; + struct rc_dev *rc; + int ret; + struct usb_host_interface *idesc; + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + rc = rc_allocate_device(); + if (!ir || !rc) { + ret = ENOMEM; + goto out; + } + + ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_ATOMIC, + &ir->dma_in); + ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); + + if (!ir->buf_in || !ir->urb_in) { + ret = ENOMEM; + goto out; + } + + idesc = intf->altsetting; + + if (idesc->desc.bNumEndpoints < 2) { + ret = -ENODEV; + goto out; + } + + ir->rc = rc; + ir->dev = &intf->dev; + ir->udev = udev; + ir->pipe_in = usb_rcvintpipe(udev, + idesc->endpoint[0].desc.bEndpointAddress); + ir->pipe_out = usb_sndintpipe(udev, + idesc->endpoint[1].desc.bEndpointAddress); + mutex_init(&ir->lock); + init_completion(&ir->completion); + + ret = iguanair_get_features(ir); + if (ret) { + dev_warn(&intf->dev, "failed to get device features"); + goto out; + } + + usb_fill_int_urb(ir->urb_in, ir->udev, ir->pipe_in, ir->buf_in, + MAX_PACKET_SIZE, iguanair_rx, ir, + idesc->endpoint[0].desc.bInterval); + ir->urb_in->transfer_dma = ir->dma_in; + ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + snprintf(ir->name, sizeof(ir->name), + "IguanaWorks USB IR Transceiver version %d.%d", + ir->version[0], ir->version[1]); + + usb_make_path(ir->udev, ir->phys, sizeof(ir->phys)); + + rc->input_name = ir->name; + rc->input_phys = ir->phys; + usb_to_input_id(ir->udev, &rc->input_id); + rc->dev.parent = &intf->dev; + rc->driver_type = RC_DRIVER_IR_RAW; + rc->allowed_protos = RC_TYPE_ALL; + rc->priv = ir; + rc->open = iguanair_open; + rc->close = iguanair_close; + rc->s_tx_mask = iguanair_set_tx_mask; + rc->s_tx_carrier = iguanair_set_tx_carrier; + rc->tx_ir = iguanair_tx; + rc->driver_name = DRIVER_NAME; + rc->map_name = RC_MAP_EMPTY; + + iguanair_set_tx_carrier(rc, 38000); + + ret = rc_register_device(rc); + if (ret < 0) { + dev_err(&intf->dev, "failed to register rc device %d", ret); + goto out; + } + + usb_set_intfdata(intf, ir); + + dev_info(&intf->dev, "Registered %s", ir->name); + + return 0; +out: + if (ir) { + usb_free_urb(ir->urb_in); + usb_free_coherent(udev, MAX_PACKET_SIZE, ir->buf_in, + ir->dma_in); + } + rc_free_device(rc); + kfree(ir); + return ret; +} + +static void __devexit iguanair_disconnect(struct usb_interface *intf) +{ + struct iguanair *ir = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + usb_kill_urb(ir->urb_in); + usb_free_urb(ir->urb_in); + usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in); + rc_unregister_device(ir->rc); + kfree(ir); +} + +static int iguanair_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct iguanair *ir = usb_get_intfdata(intf); + int rc = 0; + + mutex_lock(&ir->lock); + + if (ir->receiver_on) { + rc = iguanair_receiver(ir, false); + if (rc) + dev_warn(ir->dev, "failed to disable receiver for suspend\n"); + } + + mutex_unlock(&ir->lock); + + return rc; +} + +static int iguanair_resume(struct usb_interface *intf) +{ + struct iguanair *ir = usb_get_intfdata(intf); + int rc = 0; + + mutex_lock(&ir->lock); + + if (ir->receiver_on) { + rc = iguanair_receiver(ir, true); + if (rc) + dev_warn(ir->dev, "failed to enable receiver after resume\n"); + } + + mutex_unlock(&ir->lock); + + return rc; +} + +static const struct usb_device_id iguanair_table[] = { + { USB_DEVICE(0x1781, 0x0938) }, + { } +}; + +static struct usb_driver iguanair_driver = { + .name = DRIVER_NAME, + .probe = iguanair_probe, + .disconnect = __devexit_p(iguanair_disconnect), + .suspend = iguanair_suspend, + .resume = iguanair_resume, + .reset_resume = iguanair_resume, + .id_table = iguanair_table +}; + +module_usb_driver(iguanair_driver); + +MODULE_DESCRIPTION("IguanaWorks USB IR Transceiver"); +MODULE_AUTHOR("Sean Young <sean@mess.org>"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(usb, iguanair_table); + diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 84e06d3aa696..f38d9a8c6880 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -199,6 +199,7 @@ static bool debug; #define VENDOR_REALTEK 0x0bda #define VENDOR_TIVO 0x105a #define VENDOR_CONEXANT 0x0572 +#define VENDOR_TWISTEDMELON 0x2596 enum mceusb_model_type { MCE_GEN2 = 0, /* Most boards */ @@ -391,6 +392,12 @@ static struct usb_device_id mceusb_dev_table[] = { /* Conexant Hybrid TV RDU253S Polaris */ { USB_DEVICE(VENDOR_CONEXANT, 0x58a5), .driver_info = CX_HYBRID_TV }, + /* Twisted Melon Inc. - Manta Mini Receiver */ + { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8008) }, + /* Twisted Melon Inc. - Manta Pico Receiver */ + { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8016) }, + /* Twisted Melon Inc. - Manta Transceiver */ + { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8042) }, /* Terminating entry */ { } }; @@ -410,14 +417,12 @@ struct mceusb_dev { /* usb */ struct usb_device *usbdev; struct urb *urb_in; - struct usb_endpoint_descriptor *usb_ep_in; struct usb_endpoint_descriptor *usb_ep_out; /* buffers and dma */ unsigned char *buf_in; unsigned int len_in; dma_addr_t dma_in; - dma_addr_t dma_out; enum { CMD_HEADER = 0, @@ -686,7 +691,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem); } -static void mce_async_callback(struct urb *urb, struct pt_regs *regs) +static void mce_async_callback(struct urb *urb) { struct mceusb_dev *ir; int len; @@ -733,7 +738,7 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, pipe = usb_sndintpipe(ir->usbdev, ir->usb_ep_out->bEndpointAddress); usb_fill_int_urb(async_urb, ir->usbdev, pipe, - async_buf, size, (usb_complete_t)mce_async_callback, + async_buf, size, mce_async_callback, ir, ir->usb_ep_out->bInterval); memcpy(async_buf, data, size); @@ -1031,7 +1036,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir_raw_event_handle(ir->rc); } -static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) +static void mceusb_dev_recv(struct urb *urb) { struct mceusb_dev *ir; int buf_len; @@ -1331,7 +1336,6 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ir->model = model; /* Saving usb interface data for use by the transmitter routine */ - ir->usb_ep_in = ep_in; ir->usb_ep_out = ep_out; if (dev->descriptor.iManufacturer @@ -1349,8 +1353,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, goto rc_dev_fail; /* wire up inbound data handler */ - usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, - maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); + usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, + mceusb_dev_recv, ir, ep_in->bInterval); ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index dc8a7dddccd4..699eef39128b 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -25,6 +25,8 @@ * USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/pnp.h> @@ -123,43 +125,40 @@ static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset) return val; } -#define pr_reg(text, ...) \ - printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__) - /* dump current cir register contents */ static void cir_dump_regs(struct nvt_dev *nvt) { nvt_efm_enable(nvt); nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); - pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME); - pr_reg(" * CR CIR ACTIVE : 0x%x\n", - nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); - pr_reg(" * CR CIR BASE ADDR: 0x%x\n", - (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | + pr_info("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME); + pr_info(" * CR CIR ACTIVE : 0x%x\n", + nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); + pr_info(" * CR CIR BASE ADDR: 0x%x\n", + (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO)); - pr_reg(" * CR CIR IRQ NUM: 0x%x\n", - nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); + pr_info(" * CR CIR IRQ NUM: 0x%x\n", + nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); nvt_efm_disable(nvt); - pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME); - pr_reg(" * IRCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON)); - pr_reg(" * IRSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS)); - pr_reg(" * IREN: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN)); - pr_reg(" * RXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT)); - pr_reg(" * CP: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CP)); - pr_reg(" * CC: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CC)); - pr_reg(" * SLCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH)); - pr_reg(" * SLCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL)); - pr_reg(" * FIFOCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON)); - pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS)); - pr_reg(" * SRXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO)); - pr_reg(" * TXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT)); - pr_reg(" * STXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO)); - pr_reg(" * FCCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH)); - pr_reg(" * FCCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL)); - pr_reg(" * IRFSM: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM)); + pr_info("%s: Dump CIR registers:\n", NVT_DRIVER_NAME); + pr_info(" * IRCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON)); + pr_info(" * IRSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS)); + pr_info(" * IREN: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN)); + pr_info(" * RXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT)); + pr_info(" * CP: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CP)); + pr_info(" * CC: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CC)); + pr_info(" * SLCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH)); + pr_info(" * SLCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL)); + pr_info(" * FIFOCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON)); + pr_info(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS)); + pr_info(" * SRXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO)); + pr_info(" * TXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT)); + pr_info(" * STXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO)); + pr_info(" * FCCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH)); + pr_info(" * FCCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL)); + pr_info(" * IRFSM: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM)); } /* dump current cir wake register contents */ @@ -170,59 +169,59 @@ static void cir_wake_dump_regs(struct nvt_dev *nvt) nvt_efm_enable(nvt); nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); - pr_reg("%s: Dump CIR WAKE logical device registers:\n", - NVT_DRIVER_NAME); - pr_reg(" * CR CIR WAKE ACTIVE : 0x%x\n", - nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); - pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n", - (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | + pr_info("%s: Dump CIR WAKE logical device registers:\n", + NVT_DRIVER_NAME); + pr_info(" * CR CIR WAKE ACTIVE : 0x%x\n", + nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); + pr_info(" * CR CIR WAKE BASE ADDR: 0x%x\n", + (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO)); - pr_reg(" * CR CIR WAKE IRQ NUM: 0x%x\n", - nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); + pr_info(" * CR CIR WAKE IRQ NUM: 0x%x\n", + nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); nvt_efm_disable(nvt); - pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME); - pr_reg(" * IRCON: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON)); - pr_reg(" * IRSTS: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS)); - pr_reg(" * IREN: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN)); - pr_reg(" * FIFO CMP DEEP: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP)); - pr_reg(" * FIFO CMP TOL: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL)); - pr_reg(" * FIFO COUNT: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT)); - pr_reg(" * SLCH: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH)); - pr_reg(" * SLCL: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL)); - pr_reg(" * FIFOCON: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON)); - pr_reg(" * SRXFSTS: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS)); - pr_reg(" * SAMPLE RX FIFO: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO)); - pr_reg(" * WR FIFO DATA: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA)); - pr_reg(" * RD FIFO ONLY: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); - pr_reg(" * RD FIFO ONLY IDX: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)); - pr_reg(" * FIFO IGNORE: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE)); - pr_reg(" * IRFSM: 0x%x\n", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM)); + pr_info("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME); + pr_info(" * IRCON: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON)); + pr_info(" * IRSTS: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS)); + pr_info(" * IREN: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN)); + pr_info(" * FIFO CMP DEEP: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP)); + pr_info(" * FIFO CMP TOL: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL)); + pr_info(" * FIFO COUNT: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT)); + pr_info(" * SLCH: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH)); + pr_info(" * SLCL: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL)); + pr_info(" * FIFOCON: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON)); + pr_info(" * SRXFSTS: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS)); + pr_info(" * SAMPLE RX FIFO: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO)); + pr_info(" * WR FIFO DATA: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA)); + pr_info(" * RD FIFO ONLY: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); + pr_info(" * RD FIFO ONLY IDX: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)); + pr_info(" * FIFO IGNORE: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE)); + pr_info(" * IRFSM: 0x%x\n", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM)); fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); - pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len); - pr_reg("* Contents = "); + pr_info("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len); + pr_info("* Contents ="); for (i = 0; i < fifo_len; i++) - printk(KERN_CONT "%02x ", - nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); - printk(KERN_CONT "\n"); + pr_cont(" %02x", + nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); + pr_cont("\n"); } /* detect hardware features */ diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 6e16b09c24a9..cabc19c10515 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -775,10 +775,11 @@ static ssize_t show_protocols(struct device *device, if (dev->driver_type == RC_DRIVER_SCANCODE) { enabled = dev->rc_map.rc_type; allowed = dev->allowed_protos; - } else { + } else if (dev->raw) { enabled = dev->raw->enabled_protocols; allowed = ir_raw_get_allowed_protocols(); - } + } else + return -ENODEV; IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", (long long)allowed, diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 342c2c8c1ddf..54ee34872d14 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -232,7 +232,7 @@ MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver"); static bool txandrx; /* default = 0 */ module_param(txandrx, bool, 0444); -MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX"); +MODULE_PARM_DESC(txandrx, "Allow simultaneous TX and RX"); static unsigned int wake_sc = 0x800F040C; module_param(wake_sc, uint, 0644); @@ -1032,6 +1032,8 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) data->dev->tx_ir = wbcir_tx; data->dev->priv = data; data->dev->dev.parent = &device->dev; + data->dev->timeout = MS_TO_NS(100); + data->dev->allowed_protos = RC_TYPE_ALL; if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) { dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 99937c94d7df..c128fac0ce2c 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -5,7 +5,7 @@ config VIDEO_V4L2 tristate depends on VIDEO_DEV && VIDEO_V4L2_COMMON - default VIDEO_DEV && VIDEO_V4L2_COMMON + default y config VIDEOBUF_GEN tristate @@ -73,6 +73,7 @@ config VIDEOBUF2_DMA_SG menuconfig VIDEO_CAPTURE_DRIVERS bool "Video capture adapters" depends on VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT default y ---help--- Say Y here to enable selecting the video adapters for @@ -461,6 +462,15 @@ config VIDEO_ADV7343 To compile this driver as a module, choose M here: the module will be called adv7343. +config VIDEO_ADV7393 + tristate "ADV7393 video encoder" + depends on I2C + help + Support for Analog Devices I2C bus based ADV7393 encoder. + + To compile this driver as a module, choose M here: the + module will be called adv7393. + config VIDEO_AK881X tristate "AK8813/AK8814 video encoders" depends on I2C @@ -478,6 +488,7 @@ config VIDEO_SMIAPP_PLL config VIDEO_OV7670 tristate "OmniVision OV7670 sensor support" depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT ---help--- This is a Video4Linux2 sensor-level driver for the OmniVision OV7670 VGA camera. It currently only works with the M88ALP01 @@ -486,6 +497,7 @@ config VIDEO_OV7670 config VIDEO_VS6624 tristate "ST VS6624 sensor support" depends on VIDEO_V4L2 && I2C + depends on MEDIA_CAMERA_SUPPORT ---help--- This is a Video4Linux2 sensor-level driver for the ST VS6624 camera. @@ -496,6 +508,7 @@ config VIDEO_VS6624 config VIDEO_MT9M032 tristate "MT9M032 camera sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT select VIDEO_APTINA_PLL ---help--- This driver supports MT9M032 camera sensors from Aptina, monochrome @@ -504,6 +517,7 @@ config VIDEO_MT9M032 config VIDEO_MT9P031 tristate "Aptina MT9P031 support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT select VIDEO_APTINA_PLL ---help--- This is a Video4Linux2 sensor-level driver for the Aptina @@ -512,6 +526,7 @@ config VIDEO_MT9P031 config VIDEO_MT9T001 tristate "Aptina MT9T001 support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT ---help--- This is a Video4Linux2 sensor-level driver for the Aptina (Micron) mt0t001 3 Mpixel camera. @@ -519,6 +534,7 @@ config VIDEO_MT9T001 config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT ---help--- This is a Video4Linux2 sensor-level driver for the Micron mt0v011 1.3 Mpixel camera. It currently only works with the @@ -527,6 +543,7 @@ config VIDEO_MT9V011 config VIDEO_MT9V032 tristate "Micron MT9V032 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT ---help--- This is a Video4Linux2 sensor-level driver for the Micron MT9V032 752x480 CMOS sensor. @@ -534,6 +551,7 @@ config VIDEO_MT9V032 config VIDEO_TCM825X tristate "TCM825x camera sensor support" depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT ---help--- This is a driver for the Toshiba TCM825x VGA camera sensor. It is used for example in Nokia N800. @@ -541,12 +559,14 @@ config VIDEO_TCM825X config VIDEO_SR030PC30 tristate "Siliconfile SR030PC30 sensor support" depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT ---help--- This driver supports SR030PC30 VGA camera from Siliconfile config VIDEO_NOON010PC30 tristate "Siliconfile NOON010PC30 sensor support" depends on I2C && VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT ---help--- This driver supports NOON010PC30 CIF camera from Siliconfile @@ -554,6 +574,7 @@ source "drivers/media/video/m5mols/Kconfig" config VIDEO_S5K6AA tristate "Samsung S5K6AAFX sensor support" + depends on MEDIA_CAMERA_SUPPORT depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ---help--- This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M @@ -566,6 +587,7 @@ comment "Flash devices" config VIDEO_ADP1653 tristate "ADP1653 flash support" depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on MEDIA_CAMERA_SUPPORT ---help--- This is a driver for the ADP1653 flash controller. It is used for example in Nokia N900. @@ -573,6 +595,7 @@ config VIDEO_ADP1653 config VIDEO_AS3645A tristate "AS3645A flash driver support" depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on MEDIA_CAMERA_SUPPORT ---help--- This is a driver for the AS3645A and LM3555 flash controllers. It has build in control for flash, torch and indicator LEDs. @@ -647,30 +670,14 @@ menuconfig V4L_USB_DRIVERS depends on USB default y -if V4L_USB_DRIVERS +if V4L_USB_DRIVERS && MEDIA_CAMERA_SUPPORT -source "drivers/media/video/au0828/Kconfig" + comment "Webcam devices" source "drivers/media/video/uvc/Kconfig" source "drivers/media/video/gspca/Kconfig" -source "drivers/media/video/pvrusb2/Kconfig" - -source "drivers/media/video/hdpvr/Kconfig" - -source "drivers/media/video/em28xx/Kconfig" - -source "drivers/media/video/tlg2300/Kconfig" - -source "drivers/media/video/cx231xx/Kconfig" - -source "drivers/media/video/tm6000/Kconfig" - -source "drivers/media/video/usbvision/Kconfig" - -source "drivers/media/video/sn9c102/Kconfig" - source "drivers/media/video/pwc/Kconfig" source "drivers/media/video/cpia2/Kconfig" @@ -711,15 +718,46 @@ config USB_S2255 Say Y here if you want support for the Sensoray 2255 USB device. This driver can be compiled as a module, called s2255drv. +source "drivers/media/video/sn9c102/Kconfig" + +endif # V4L_USB_DRIVERS && MEDIA_CAMERA_SUPPORT + +if V4L_USB_DRIVERS + + comment "Webcam and/or TV USB devices" + +source "drivers/media/video/em28xx/Kconfig" + +endif + +if V4L_USB_DRIVERS && MEDIA_ANALOG_TV_SUPPORT + + comment "TV USB devices" + +source "drivers/media/video/au0828/Kconfig" + +source "drivers/media/video/pvrusb2/Kconfig" + +source "drivers/media/video/hdpvr/Kconfig" + +source "drivers/media/video/tlg2300/Kconfig" + +source "drivers/media/video/cx231xx/Kconfig" + +source "drivers/media/video/tm6000/Kconfig" + +source "drivers/media/video/usbvision/Kconfig" + endif # V4L_USB_DRIVERS # -# PCI drivers configuration +# PCI drivers configuration - No devices here are for webcams # menuconfig V4L_PCI_DRIVERS bool "V4L PCI(e) devices" depends on PCI + depends on MEDIA_ANALOG_TV_SUPPORT default y ---help--- Say Y here to enable support for these PCI(e) drivers. @@ -814,11 +852,13 @@ endif # V4L_PCI_DRIVERS # # ISA & parallel port drivers configuration +# All devices here are webcam or grabber devices # menuconfig V4L_ISA_PARPORT_DRIVERS bool "V4L ISA and parallel port devices" depends on ISA || PARPORT + depends on MEDIA_CAMERA_SUPPORT default n ---help--- Say Y here to enable support for these ISA and parallel port drivers. @@ -871,8 +911,13 @@ config VIDEO_W9966 endif # V4L_ISA_PARPORT_DRIVERS +# +# Platform drivers +# All drivers here are currently for webcam support + menuconfig V4L_PLATFORM_DRIVERS bool "V4L platform devices" + depends on MEDIA_CAMERA_SUPPORT default n ---help--- Say Y here to enable support for platform-specific V4L drivers. diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index d209de0e0ca8..b7da9faa3b0a 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o +obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o obj-$(CONFIG_VIDEO_VS6624) += vs6624.o obj-$(CONFIG_VIDEO_BT819) += bt819.o diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c index 174bffacf117..45ecf8db1eae 100644 --- a/drivers/media/video/adv7180.c +++ b/drivers/media/video/adv7180.c @@ -26,11 +26,10 @@ #include <media/v4l2-ioctl.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> #include <media/v4l2-chip-ident.h> #include <linux/mutex.h> -#define DRIVER_NAME "adv7180" - #define ADV7180_INPUT_CONTROL_REG 0x00 #define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00 #define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10 @@ -55,21 +54,21 @@ #define ADV7180_AUTODETECT_ENABLE_REG 0x07 #define ADV7180_AUTODETECT_DEFAULT 0x7f - +/* Contrast */ #define ADV7180_CON_REG 0x08 /*Unsigned */ -#define CON_REG_MIN 0 -#define CON_REG_DEF 128 -#define CON_REG_MAX 255 - +#define ADV7180_CON_MIN 0 +#define ADV7180_CON_DEF 128 +#define ADV7180_CON_MAX 255 +/* Brightness*/ #define ADV7180_BRI_REG 0x0a /*Signed */ -#define BRI_REG_MIN -128 -#define BRI_REG_DEF 0 -#define BRI_REG_MAX 127 - +#define ADV7180_BRI_MIN -128 +#define ADV7180_BRI_DEF 0 +#define ADV7180_BRI_MAX 127 +/* Hue */ #define ADV7180_HUE_REG 0x0b /*Signed, inverted */ -#define HUE_REG_MIN -127 -#define HUE_REG_DEF 0 -#define HUE_REG_MAX 128 +#define ADV7180_HUE_MIN -127 +#define ADV7180_HUE_DEF 0 +#define ADV7180_HUE_MAX 128 #define ADV7180_ADI_CTRL_REG 0x0e #define ADV7180_ADI_CTRL_IRQ_SPACE 0x20 @@ -98,12 +97,12 @@ #define ADV7180_ICONF1_ACTIVE_LOW 0x01 #define ADV7180_ICONF1_PSYNC_ONLY 0x10 #define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 - +/* Saturation */ #define ADV7180_SD_SAT_CB_REG 0xe3 /*Unsigned */ #define ADV7180_SD_SAT_CR_REG 0xe4 /*Unsigned */ -#define SAT_REG_MIN 0 -#define SAT_REG_DEF 128 -#define SAT_REG_MAX 255 +#define ADV7180_SAT_MIN 0 +#define ADV7180_SAT_DEF 128 +#define ADV7180_SAT_MAX 255 #define ADV7180_IRQ1_LOCK 0x01 #define ADV7180_IRQ1_UNLOCK 0x02 @@ -121,18 +120,18 @@ #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F struct adv7180_state { + struct v4l2_ctrl_handler ctrl_hdl; struct v4l2_subdev sd; struct work_struct work; struct mutex mutex; /* mutual excl. when accessing chip */ int irq; v4l2_std_id curr_norm; bool autodetect; - s8 brightness; - s16 hue; - u8 contrast; - u8 saturation; u8 input; }; +#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ + struct adv7180_state, \ + ctrl_hdl)->sd) static v4l2_std_id adv7180_std_to_v4l2(u8 status1) { @@ -237,7 +236,7 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, if (ret) return ret; - /*We cannot discriminate between LQFP and 40-pin LFCSP, so accept + /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept * all inputs and let the card driver take care of validation */ if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input) @@ -316,117 +315,39 @@ out: return ret; } -static int adv7180_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, BRI_REG_MIN, BRI_REG_MAX, - 1, BRI_REG_DEF); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, HUE_REG_MIN, HUE_REG_MAX, - 1, HUE_REG_DEF); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, CON_REG_MIN, CON_REG_MAX, - 1, CON_REG_DEF); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, SAT_REG_MIN, SAT_REG_MAX, - 1, SAT_REG_DEF); - default: - break; - } - - return -EINVAL; -} - -static int adv7180_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct adv7180_state *state = to_state(sd); - int ret = mutex_lock_interruptible(&state->mutex); - if (ret) - return ret; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = state->brightness; - break; - case V4L2_CID_HUE: - ctrl->value = state->hue; - break; - case V4L2_CID_CONTRAST: - ctrl->value = state->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = state->saturation; - break; - default: - ret = -EINVAL; - } - - mutex_unlock(&state->mutex); - return ret; -} - -static int adv7180_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) { + struct v4l2_subdev *sd = to_adv7180_sd(ctrl); struct adv7180_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = mutex_lock_interruptible(&state->mutex); + int val; + if (ret) return ret; - + val = ctrl->val; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - if ((ctrl->value > BRI_REG_MAX) - || (ctrl->value < BRI_REG_MIN)) { - ret = -ERANGE; - break; - } - state->brightness = ctrl->value; - ret = i2c_smbus_write_byte_data(client, - ADV7180_BRI_REG, - state->brightness); + ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val); break; case V4L2_CID_HUE: - if ((ctrl->value > HUE_REG_MAX) - || (ctrl->value < HUE_REG_MIN)) { - ret = -ERANGE; - break; - } - state->hue = ctrl->value; /*Hue is inverted according to HSL chart */ - ret = i2c_smbus_write_byte_data(client, - ADV7180_HUE_REG, -state->hue); + ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val); break; case V4L2_CID_CONTRAST: - if ((ctrl->value > CON_REG_MAX) - || (ctrl->value < CON_REG_MIN)) { - ret = -ERANGE; - break; - } - state->contrast = ctrl->value; - ret = i2c_smbus_write_byte_data(client, - ADV7180_CON_REG, - state->contrast); + ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val); break; case V4L2_CID_SATURATION: - if ((ctrl->value > SAT_REG_MAX) - || (ctrl->value < SAT_REG_MIN)) { - ret = -ERANGE; - break; - } /* *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE *Let's not confuse the user, everybody understands saturation */ - state->saturation = ctrl->value; - ret = i2c_smbus_write_byte_data(client, - ADV7180_SD_SAT_CB_REG, - state->saturation); + ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG, + val); if (ret < 0) break; - ret = i2c_smbus_write_byte_data(client, - ADV7180_SD_SAT_CR_REG, - state->saturation); + ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG, + val); break; default: ret = -EINVAL; @@ -436,6 +357,42 @@ static int adv7180_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return ret; } +static const struct v4l2_ctrl_ops adv7180_ctrl_ops = { + .s_ctrl = adv7180_s_ctrl, +}; + +static int adv7180_init_controls(struct adv7180_state *state) +{ + v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); + + v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, + V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, + ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF); + v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, + V4L2_CID_CONTRAST, ADV7180_CON_MIN, + ADV7180_CON_MAX, 1, ADV7180_CON_DEF); + v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, + V4L2_CID_SATURATION, ADV7180_SAT_MIN, + ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF); + v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, + V4L2_CID_HUE, ADV7180_HUE_MIN, + ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); + state->sd.ctrl_handler = &state->ctrl_hdl; + if (state->ctrl_hdl.error) { + int err = state->ctrl_hdl.error; + + v4l2_ctrl_handler_free(&state->ctrl_hdl); + return err; + } + v4l2_ctrl_handler_setup(&state->ctrl_hdl); + + return 0; +} +static void adv7180_exit_controls(struct adv7180_state *state) +{ + v4l2_ctrl_handler_free(&state->ctrl_hdl); +} + static const struct v4l2_subdev_video_ops adv7180_video_ops = { .querystd = adv7180_querystd, .g_input_status = adv7180_g_input_status, @@ -445,9 +402,9 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { static const struct v4l2_subdev_core_ops adv7180_core_ops = { .g_chip_ident = adv7180_g_chip_ident, .s_std = adv7180_s_std, - .queryctrl = adv7180_queryctrl, - .g_ctrl = adv7180_g_ctrl, - .s_ctrl = adv7180_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, }; static const struct v4l2_subdev_ops adv7180_ops = { @@ -539,7 +496,7 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state) /* register for interrupts */ if (state->irq > 0) { - ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME, + ret = request_irq(state->irq, adv7180_irq, 0, KBUILD_MODNAME, state); if (ret) return ret; @@ -580,31 +537,6 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state) return ret; } - /*Set default value for controls */ - ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, - state->brightness); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, state->hue); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, - state->contrast); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG, - state->saturation); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG, - state->saturation); - if (ret < 0) - return ret; - return 0; } @@ -632,25 +564,26 @@ static __devinit int adv7180_probe(struct i2c_client *client, INIT_WORK(&state->work, adv7180_work); mutex_init(&state->mutex); state->autodetect = true; - state->brightness = BRI_REG_DEF; - state->hue = HUE_REG_DEF; - state->contrast = CON_REG_DEF; - state->saturation = SAT_REG_DEF; state->input = 0; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7180_ops); - ret = init_device(client, state); - if (0 != ret) + ret = adv7180_init_controls(state); + if (ret) goto err_unreg_subdev; + ret = init_device(client, state); + if (ret) + goto err_free_ctrl; return 0; +err_free_ctrl: + adv7180_exit_controls(state); err_unreg_subdev: mutex_destroy(&state->mutex); v4l2_device_unregister_subdev(sd); kfree(state); err: - printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret); + printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret); return ret; } @@ -678,7 +611,7 @@ static __devexit int adv7180_remove(struct i2c_client *client) } static const struct i2c_device_id adv7180_id[] = { - {DRIVER_NAME, 0}, + {KBUILD_MODNAME, 0}, {}, }; @@ -716,7 +649,7 @@ MODULE_DEVICE_TABLE(i2c, adv7180_id); static struct i2c_driver adv7180_driver = { .driver = { .owner = THIS_MODULE, - .name = DRIVER_NAME, + .name = KBUILD_MODNAME, }, .probe = adv7180_probe, .remove = __devexit_p(adv7180_remove), diff --git a/drivers/media/video/adv7393.c b/drivers/media/video/adv7393.c new file mode 100644 index 000000000000..3dc6098c7267 --- /dev/null +++ b/drivers/media/video/adv7393.c @@ -0,0 +1,487 @@ +/* + * adv7393 - ADV7393 Video Encoder Driver + * + * The encoder hardware does not support SECAM. + * + * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/ + * Benoît Thébaudeau <benoit.thebaudeau@advansee.com> + * + * Based on ADV7343 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/slab.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 <media/adv7393.h> +#include <media/v4l2-device.h> +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-ctrls.h> + +#include "adv7393_regs.h" + +MODULE_DESCRIPTION("ADV7393 video encoder driver"); +MODULE_LICENSE("GPL"); + +static bool debug; +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "Debug level 0-1"); + +struct adv7393_state { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + u8 reg00; + u8 reg01; + u8 reg02; + u8 reg35; + u8 reg80; + u8 reg82; + u32 output; + v4l2_std_id std; +}; + +static inline struct adv7393_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct adv7393_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct adv7393_state, hdl)->sd; +} + +static inline int adv7393_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 adv7393_init_reg_val[] = { + ADV7393_SOFT_RESET, ADV7393_SOFT_RESET_DEFAULT, + ADV7393_POWER_MODE_REG, ADV7393_POWER_MODE_REG_DEFAULT, + + ADV7393_HD_MODE_REG1, ADV7393_HD_MODE_REG1_DEFAULT, + ADV7393_HD_MODE_REG2, ADV7393_HD_MODE_REG2_DEFAULT, + ADV7393_HD_MODE_REG3, ADV7393_HD_MODE_REG3_DEFAULT, + ADV7393_HD_MODE_REG4, ADV7393_HD_MODE_REG4_DEFAULT, + ADV7393_HD_MODE_REG5, ADV7393_HD_MODE_REG5_DEFAULT, + ADV7393_HD_MODE_REG6, ADV7393_HD_MODE_REG6_DEFAULT, + ADV7393_HD_MODE_REG7, ADV7393_HD_MODE_REG7_DEFAULT, + + ADV7393_SD_MODE_REG1, ADV7393_SD_MODE_REG1_DEFAULT, + ADV7393_SD_MODE_REG2, ADV7393_SD_MODE_REG2_DEFAULT, + ADV7393_SD_MODE_REG3, ADV7393_SD_MODE_REG3_DEFAULT, + ADV7393_SD_MODE_REG4, ADV7393_SD_MODE_REG4_DEFAULT, + ADV7393_SD_MODE_REG5, ADV7393_SD_MODE_REG5_DEFAULT, + ADV7393_SD_MODE_REG6, ADV7393_SD_MODE_REG6_DEFAULT, + ADV7393_SD_MODE_REG7, ADV7393_SD_MODE_REG7_DEFAULT, + ADV7393_SD_MODE_REG8, ADV7393_SD_MODE_REG8_DEFAULT, + + ADV7393_SD_TIMING_REG0, ADV7393_SD_TIMING_REG0_DEFAULT, + + ADV7393_SD_HUE_ADJUST, ADV7393_SD_HUE_ADJUST_DEFAULT, + ADV7393_SD_CGMS_WSS0, ADV7393_SD_CGMS_WSS0_DEFAULT, + ADV7393_SD_BRIGHTNESS_WSS, ADV7393_SD_BRIGHTNESS_WSS_DEFAULT, +}; + +/* + * 2^32 + * FSC(reg) = FSC (HZ) * -------- + * 27000000 + */ +static const struct adv7393_std_info stdinfo[] = { + { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443, + }, { + /* 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 Hz */ + 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_M, 705268427, V4L2_STD_PAL_60, + }, { + /* FSC(Hz) = 4,433,618.75 Hz */ + SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL, + }, +}; + +static int adv7393_setstd(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7393_state *state = to_state(sd); + const struct adv7393_std_info *std_info; + int num_std; + u8 reg; + u32 val; + int err = 0; + int i; + + num_std = ARRAY_SIZE(stdinfo); + + for (i = 0; i < num_std; i++) { + if (stdinfo[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; + } + + std_info = &stdinfo[i]; + + /* Set the standard */ + val = state->reg80 & ~SD_STD_MASK; + val |= std_info->standard_val3; + err = adv7393_write(sd, ADV7393_SD_MODE_REG1, val); + if (err < 0) + goto setstd_exit; + + state->reg80 = val; + + /* Configure the input mode register */ + val = state->reg01 & ~INPUT_MODE_MASK; + val |= SD_INPUT_MODE; + err = adv7393_write(sd, ADV7393_MODE_SELECT_REG, val); + if (err < 0) + goto setstd_exit; + + state->reg01 = val; + + /* Program the sub carrier frequency registers */ + val = std_info->fsc_val; + for (reg = ADV7393_FSC_REG0; reg <= ADV7393_FSC_REG3; reg++) { + err = adv7393_write(sd, reg, val); + if (err < 0) + goto setstd_exit; + val >>= 8; + } + + val = state->reg82; + + /* Pedestal settings */ + if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443)) + val |= SD_PEDESTAL_EN; + else + val &= SD_PEDESTAL_DI; + + err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val); + if (err < 0) + goto setstd_exit; + + state->reg82 = val; + +setstd_exit: + if (err != 0) + v4l2_err(sd, "Error setting std, write failed\n"); + + return err; +} + +static int adv7393_setoutput(struct v4l2_subdev *sd, u32 output_type) +{ + struct adv7393_state *state = to_state(sd); + u8 val; + int err = 0; + + if (output_type > ADV7393_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 == ADV7393_COMPOSITE_ID) + val |= ADV7393_COMPOSITE_POWER_VALUE; + else if (output_type == ADV7393_COMPONENT_ID) + val |= ADV7393_COMPONENT_POWER_VALUE; + else + val |= ADV7393_SVIDEO_POWER_VALUE; + + err = adv7393_write(sd, ADV7393_POWER_MODE_REG, val); + if (err < 0) + goto setoutput_exit; + + state->reg00 = val; + + /* Enable YUV output */ + val = state->reg02 | YUV_OUTPUT_SELECT; + err = adv7393_write(sd, ADV7393_MODE_REG0, val); + if (err < 0) + goto setoutput_exit; + + state->reg02 = val; + + /* configure SD DAC Output 1 bit */ + val = state->reg82; + if (output_type == ADV7393_COMPONENT_ID) + val &= SD_DAC_OUT1_DI; + else + val |= SD_DAC_OUT1_EN; + err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val); + if (err < 0) + goto setoutput_exit; + + state->reg82 = val; + + /* configure ED/HD Color DAC Swap bit to zero */ + val = state->reg35 & HD_DAC_SWAP_DI; + err = adv7393_write(sd, ADV7393_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 adv7393_log_status(struct v4l2_subdev *sd) +{ + struct adv7393_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 adv7393_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + return adv7393_write(sd, ADV7393_SD_BRIGHTNESS_WSS, + ctrl->val & SD_BRIGHTNESS_VALUE_MASK); + + case V4L2_CID_HUE: + return adv7393_write(sd, ADV7393_SD_HUE_ADJUST, + ctrl->val - ADV7393_HUE_MIN); + + case V4L2_CID_GAIN: + return adv7393_write(sd, ADV7393_DAC123_OUTPUT_LEVEL, + ctrl->val); + } + return -EINVAL; +} + +static int adv7393_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_ADV7393, 0); +} + +static const struct v4l2_ctrl_ops adv7393_ctrl_ops = { + .s_ctrl = adv7393_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops adv7393_core_ops = { + .log_status = adv7393_log_status, + .g_chip_ident = adv7393_g_chip_ident, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, +}; + +static int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct adv7393_state *state = to_state(sd); + int err = 0; + + if (state->std == std) + return 0; + + err = adv7393_setstd(sd, std); + if (!err) + state->std = std; + + return err; +} + +static int adv7393_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct adv7393_state *state = to_state(sd); + int err = 0; + + if (state->output == output) + return 0; + + err = adv7393_setoutput(sd, output); + if (!err) + state->output = output; + + return err; +} + +static const struct v4l2_subdev_video_ops adv7393_video_ops = { + .s_std_output = adv7393_s_std_output, + .s_routing = adv7393_s_routing, +}; + +static const struct v4l2_subdev_ops adv7393_ops = { + .core = &adv7393_core_ops, + .video = &adv7393_video_ops, +}; + +static int adv7393_initialize(struct v4l2_subdev *sd) +{ + struct adv7393_state *state = to_state(sd); + int err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(adv7393_init_reg_val); i += 2) { + + err = adv7393_write(sd, adv7393_init_reg_val[i], + adv7393_init_reg_val[i+1]); + if (err) { + v4l2_err(sd, "Error initializing\n"); + return err; + } + } + + /* Configure for default video standard */ + err = adv7393_setoutput(sd, state->output); + if (err < 0) { + v4l2_err(sd, "Error setting output during init\n"); + return -EINVAL; + } + + err = adv7393_setstd(sd, state->std); + if (err < 0) { + v4l2_err(sd, "Error setting std during init\n"); + return -EINVAL; + } + + return err; +} + +static int adv7393_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adv7393_state *state; + int err; + + 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 adv7393_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + state->reg00 = ADV7393_POWER_MODE_REG_DEFAULT; + state->reg01 = 0x00; + state->reg02 = 0x20; + state->reg35 = ADV7393_HD_MODE_REG6_DEFAULT; + state->reg80 = ADV7393_SD_MODE_REG1_DEFAULT; + state->reg82 = ADV7393_SD_MODE_REG2_DEFAULT; + + state->output = ADV7393_COMPOSITE_ID; + state->std = V4L2_STD_NTSC; + + v4l2_i2c_subdev_init(&state->sd, client, &adv7393_ops); + + v4l2_ctrl_handler_init(&state->hdl, 3); + v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops, + V4L2_CID_BRIGHTNESS, ADV7393_BRIGHTNESS_MIN, + ADV7393_BRIGHTNESS_MAX, 1, + ADV7393_BRIGHTNESS_DEF); + v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops, + V4L2_CID_HUE, ADV7393_HUE_MIN, + ADV7393_HUE_MAX, 1, + ADV7393_HUE_DEF); + v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops, + V4L2_CID_GAIN, ADV7393_GAIN_MIN, + ADV7393_GAIN_MAX, 1, + ADV7393_GAIN_DEF); + state->sd.ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + v4l2_ctrl_handler_setup(&state->hdl); + + err = adv7393_initialize(&state->sd); + if (err) { + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + } + return err; +} + +static int adv7393_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct adv7393_state *state = to_state(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + + return 0; +} + +static const struct i2c_device_id adv7393_id[] = { + {"adv7393", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, adv7393_id); + +static struct i2c_driver adv7393_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv7393", + }, + .probe = adv7393_probe, + .remove = adv7393_remove, + .id_table = adv7393_id, +}; +module_i2c_driver(adv7393_driver); diff --git a/drivers/media/video/adv7393_regs.h b/drivers/media/video/adv7393_regs.h new file mode 100644 index 000000000000..78968330f0be --- /dev/null +++ b/drivers/media/video/adv7393_regs.h @@ -0,0 +1,188 @@ +/* + * ADV7393 encoder related structure and register definitions + * + * Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/ + * Benoît Thébaudeau <benoit.thebaudeau@advansee.com> + * + * Based on ADV7343 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. + */ + +#ifndef ADV7393_REGS_H +#define ADV7393_REGS_H + +struct adv7393_std_info { + u32 standard_val3; + u32 fsc_val; + v4l2_std_id stdid; +}; + +/* Register offset macros */ +#define ADV7393_POWER_MODE_REG (0x00) +#define ADV7393_MODE_SELECT_REG (0x01) +#define ADV7393_MODE_REG0 (0x02) + +#define ADV7393_DAC123_OUTPUT_LEVEL (0x0B) + +#define ADV7393_SOFT_RESET (0x17) + +#define ADV7393_HD_MODE_REG1 (0x30) +#define ADV7393_HD_MODE_REG2 (0x31) +#define ADV7393_HD_MODE_REG3 (0x32) +#define ADV7393_HD_MODE_REG4 (0x33) +#define ADV7393_HD_MODE_REG5 (0x34) +#define ADV7393_HD_MODE_REG6 (0x35) + +#define ADV7393_HD_MODE_REG7 (0x39) + +#define ADV7393_SD_MODE_REG1 (0x80) +#define ADV7393_SD_MODE_REG2 (0x82) +#define ADV7393_SD_MODE_REG3 (0x83) +#define ADV7393_SD_MODE_REG4 (0x84) +#define ADV7393_SD_MODE_REG5 (0x86) +#define ADV7393_SD_MODE_REG6 (0x87) +#define ADV7393_SD_MODE_REG7 (0x88) +#define ADV7393_SD_MODE_REG8 (0x89) + +#define ADV7393_SD_TIMING_REG0 (0x8A) + +#define ADV7393_FSC_REG0 (0x8C) +#define ADV7393_FSC_REG1 (0x8D) +#define ADV7393_FSC_REG2 (0x8E) +#define ADV7393_FSC_REG3 (0x8F) + +#define ADV7393_SD_CGMS_WSS0 (0x99) + +#define ADV7393_SD_HUE_ADJUST (0xA0) +#define ADV7393_SD_BRIGHTNESS_WSS (0xA1) + +/* Default values for the registers */ +#define ADV7393_POWER_MODE_REG_DEFAULT (0x10) +#define ADV7393_HD_MODE_REG1_DEFAULT (0x3C) /* Changed Default + 720p EAV/SAV code*/ +#define ADV7393_HD_MODE_REG2_DEFAULT (0x01) /* Changed Pixel data + valid */ +#define ADV7393_HD_MODE_REG3_DEFAULT (0x00) /* Color delay 0 clks */ +#define ADV7393_HD_MODE_REG4_DEFAULT (0xEC) /* Changed */ +#define ADV7393_HD_MODE_REG5_DEFAULT (0x08) +#define ADV7393_HD_MODE_REG6_DEFAULT (0x00) +#define ADV7393_HD_MODE_REG7_DEFAULT (0x00) +#define ADV7393_SOFT_RESET_DEFAULT (0x02) +#define ADV7393_COMPOSITE_POWER_VALUE (0x10) +#define ADV7393_COMPONENT_POWER_VALUE (0x1C) +#define ADV7393_SVIDEO_POWER_VALUE (0x0C) +#define ADV7393_SD_HUE_ADJUST_DEFAULT (0x80) +#define ADV7393_SD_BRIGHTNESS_WSS_DEFAULT (0x00) + +#define ADV7393_SD_CGMS_WSS0_DEFAULT (0x10) + +#define ADV7393_SD_MODE_REG1_DEFAULT (0x10) +#define ADV7393_SD_MODE_REG2_DEFAULT (0xC9) +#define ADV7393_SD_MODE_REG3_DEFAULT (0x00) +#define ADV7393_SD_MODE_REG4_DEFAULT (0x00) +#define ADV7393_SD_MODE_REG5_DEFAULT (0x02) +#define ADV7393_SD_MODE_REG6_DEFAULT (0x8C) +#define ADV7393_SD_MODE_REG7_DEFAULT (0x14) +#define ADV7393_SD_MODE_REG8_DEFAULT (0x00) + +#define ADV7393_SD_TIMING_REG0_DEFAULT (0x0C) + +/* 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 SD brightness/WSS */ +#define SD_BRIGHTNESS_VALUE_MASK (0x7F) +#define SD_BLANK_WSS_DATA_MASK (0x80) + +/* 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_MASK (0x1F) +#define STD_MODE_SHIFT (3) +#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_25 (0x0E) +#define STD_MODE_1080P_24 (0x11) +#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 (0x07) +#define SD_LUMA_FLTR_SHIFT (2) +#define SD_CHROMA_FLTR_MASK (0x07) +#define SD_CHROMA_FLTR_SHIFT (5) + +/* Bit masks for SD Mode Register 2 */ +#define SD_PRPB_SSAF_EN (0x01) +#define SD_PRPB_SSAF_DI (0xFE) +#define SD_DAC_OUT1_EN (0x02) +#define SD_DAC_OUT1_DI (0xFD) +#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_PRPB_SYNC_EN (0x04) +#define HD_PRPB_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_MODEA (0xBF) +#define HD_ADPT_FLTR_MODEB (0x40) +#define HD_ADPT_FLTR_EN (0x80) +#define HD_ADPT_FLTR_DI (0x7F) + +#define ADV7393_BRIGHTNESS_MAX (63) +#define ADV7393_BRIGHTNESS_MIN (-64) +#define ADV7393_BRIGHTNESS_DEF (0) +#define ADV7393_HUE_MAX (127) +#define ADV7393_HUE_MIN (-128) +#define ADV7393_HUE_DEF (0) +#define ADV7393_GAIN_MAX (64) +#define ADV7393_GAIN_MIN (-64) +#define ADV7393_GAIN_DEF (0) + +#endif diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 856ab962cd63..38952faaffda 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -345,7 +345,7 @@ static struct CARD { { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" }, { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" }, { 0x3116f200, BTTV_BOARD_TVT_TD3116, "Tongwei Video Technology TD-3116" }, - + { 0x02280279, BTTV_BOARD_APOSONIC_WDVR, "Aposonic W-DVR" }, { 0, -1, NULL } }; @@ -676,6 +676,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .has_remote = 1, + .has_radio = 1, /* not every card has radio */ }, [BTTV_BOARD_VOBIS_BOOSTAR] = { .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar", @@ -2817,6 +2818,14 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .tuner_type = TUNER_ABSENT, }, + [BTTV_BOARD_APOSONIC_WDVR] = { + .name = "Aposonic W-DVR", + .video_inputs = 4, + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = TUNER_ABSENT, + }, + }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index ff7a589d8e0f..b58ff87db771 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -558,12 +558,6 @@ static const struct bttv_format formats[] = { .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .btformat = BT848_COLOR_FMT_YUY2, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .btformat = BT848_COLOR_FMT_YUY2, diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index acfe2f3b92d9..79a11240a590 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -184,7 +184,7 @@ #define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e #define BTTV_BOARD_PV183 0x9f #define BTTV_BOARD_TVT_TD3116 0xa0 - +#define BTTV_BOARD_APOSONIC_WDVR 0xa1 /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 55e92902a76c..a62a7b739991 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -932,7 +932,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) buf->sequence = cam->buffers[buf->index].seq; buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; buf->length = cam->frame_size; - buf->input = 0; + buf->reserved2 = 0; buf->reserved = 0; memset(&buf->timecode, 0, sizeof(buf->timecode)); diff --git a/drivers/media/video/cs8420.h b/drivers/media/video/cs8420.h deleted file mode 100644 index 621c0c6678ea..000000000000 --- a/drivers/media/video/cs8420.h +++ /dev/null @@ -1,50 +0,0 @@ -/* cs8420.h - cs8420 initializations - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ -#ifndef __CS8420_H__ -#define __CS8420_H__ - -/* Initialization Sequence */ - -static __u8 init8420[] = { - 1, 0x01, 2, 0x02, 3, 0x00, 4, 0x46, - 5, 0x24, 6, 0x84, 18, 0x18, 19, 0x13, -}; - -#define INIT8420LEN (sizeof(init8420)/2) - -static __u8 mode8420pro[] = { /* professional output mode */ - 32, 0xa1, 33, 0x00, 34, 0x00, 35, 0x00, - 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, - 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, - 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, - 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, - 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, -}; -#define MODE8420LEN (sizeof(mode8420pro)/2) - -static __u8 mode8420con[] = { /* consumer output mode */ - 32, 0x20, 33, 0x00, 34, 0x00, 35, 0x48, - 36, 0x00, 37, 0x00, 38, 0x00, 39, 0x00, - 40, 0x00, 41, 0x00, 42, 0x00, 43, 0x00, - 44, 0x00, 45, 0x00, 46, 0x00, 47, 0x00, - 48, 0x00, 49, 0x00, 50, 0x00, 51, 0x00, - 52, 0x00, 53, 0x00, 54, 0x00, 55, 0x00, -}; - -#endif diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 35fde4e931f5..e9912db3b496 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -1142,24 +1142,6 @@ static long cx18_default(struct file *file, void *fh, bool valid_prio, return 0; } -long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct video_device *vfd = video_devdata(filp); - struct cx18_open_id *id = file2id(filp); - struct cx18 *cx = id->cx; - long res; - - mutex_lock(&cx->serialize_lock); - - if (cx18_debug & CX18_DBGFLG_IOCTL) - vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; - res = video_ioctl2(filp, cmd, arg); - vfd->debug = 0; - mutex_unlock(&cx->serialize_lock); - return res; -} - static const struct v4l2_ioctl_ops cx18_ioctl_ops = { .vidioc_querycap = cx18_querycap, .vidioc_s_audio = cx18_s_audio, diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h index dcb2559ad520..2f9dd591ee0f 100644 --- a/drivers/media/video/cx18/cx18-ioctl.h +++ b/drivers/media/video/cx18/cx18-ioctl.h @@ -29,5 +29,3 @@ void cx18_set_funcs(struct video_device *vdev); int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); int cx18_s_input(struct file *file, void *fh, unsigned int inp); -long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg); diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 4185bcb80ca3..9d598ab88615 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -40,8 +40,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = { .owner = THIS_MODULE, .read = cx18_v4l2_read, .open = cx18_v4l2_open, - /* FIXME change to video_ioctl2 if serialization lock can be removed */ - .unlocked_ioctl = cx18_v4l2_ioctl, + .unlocked_ioctl = video_ioctl2, .release = cx18_v4l2_close, .poll = cx18_v4l2_enc_poll, .mmap = cx18_v4l2_mmap, @@ -376,6 +375,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type) s->video_dev->fops = &cx18_v4l2_enc_fops; s->video_dev->release = video_device_release; s->video_dev->tvnorms = V4L2_STD_ALL; + s->video_dev->lock = &cx->serialize_lock; set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags); cx18_set_funcs(s->video_dev); return 0; diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c index 068f78dc5d13..b4c99c7270cf 100644 --- a/drivers/media/video/cx231xx/cx231xx-audio.c +++ b/drivers/media/video/cx231xx/cx231xx-audio.c @@ -307,7 +307,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvisocpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->interval = 1; urb->complete = cx231xx_audio_isocirq; @@ -368,7 +368,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvbulkpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + urb->transfer_flags = 0; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->complete = cx231xx_audio_bulkirq; urb->transfer_buffer_length = sb_size; diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c index b085a3c6dc04..447148eff958 100644 --- a/drivers/media/video/cx231xx/cx231xx-avcore.c +++ b/drivers/media/video/cx231xx/cx231xx-avcore.c @@ -89,7 +89,7 @@ void initGPIO(struct cx231xx *dev) verve_read_byte(dev, 0x07, &val); cx231xx_info(" verve_read_byte address0x07=0x%x\n", val); - cx231xx_capture_start(dev, 1, 2); + cx231xx_capture_start(dev, 1, Vbi); cx231xx_mode_register(dev, EP_MODE_SET, 0x0500FE00); cx231xx_mode_register(dev, GBULK_BIT_EN, 0xFFFDFFFF); @@ -99,7 +99,7 @@ void uninitGPIO(struct cx231xx *dev) { u8 value[4] = { 0, 0, 0, 0 }; - cx231xx_capture_start(dev, 0, 2); + cx231xx_capture_start(dev, 0, Vbi); verve_write_byte(dev, 0x07, 0x14); cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, 0x68, value, 4); @@ -2516,29 +2516,29 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type) if (dev->udev->speed == USB_SPEED_HIGH) { switch (media_type) { - case 81: /* audio */ + case Audio: cx231xx_info("%s: Audio enter HANC\n", __func__); status = cx231xx_mode_register(dev, TS_MODE_REG, 0x9300); break; - case 2: /* vbi */ + case Vbi: cx231xx_info("%s: set vanc registers\n", __func__); status = cx231xx_mode_register(dev, TS_MODE_REG, 0x300); break; - case 3: /* sliced cc */ + case Sliced_cc: cx231xx_info("%s: set hanc registers\n", __func__); status = cx231xx_mode_register(dev, TS_MODE_REG, 0x1300); break; - case 0: /* video */ + case Raw_Video: cx231xx_info("%s: set video registers\n", __func__); status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100); break; - case 4: /* ts1 */ + case TS1_serial_mode: cx231xx_info("%s: set ts1 registers", __func__); if (dev->board.has_417) { @@ -2569,7 +2569,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type) } break; - case 6: /* ts1 parallel mode */ + case TS1_parallel_mode: cx231xx_info("%s: set ts1 parallel mode registers\n", __func__); status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100); @@ -2592,52 +2592,28 @@ int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type) /* get EP for media type */ pcb_config = (struct pcb_config *)&dev->current_pcb_config; - if (pcb_config->config_num == 1) { + if (pcb_config->config_num) { switch (media_type) { - case 0: /* Video */ + case Raw_Video: ep_mask = ENABLE_EP4; /* ep4 [00:1000] */ break; - case 1: /* Audio */ + case Audio: ep_mask = ENABLE_EP3; /* ep3 [00:0100] */ break; - case 2: /* Vbi */ + case Vbi: ep_mask = ENABLE_EP5; /* ep5 [01:0000] */ break; - case 3: /* Sliced_cc */ + case Sliced_cc: ep_mask = ENABLE_EP6; /* ep6 [10:0000] */ break; - case 4: /* ts1 */ - case 6: /* ts1 parallel mode */ + case TS1_serial_mode: + case TS1_parallel_mode: ep_mask = ENABLE_EP1; /* ep1 [00:0001] */ break; - case 5: /* ts2 */ + case TS2: ep_mask = ENABLE_EP2; /* ep2 [00:0010] */ break; } - - } else if (pcb_config->config_num > 1) { - switch (media_type) { - case 0: /* Video */ - ep_mask = ENABLE_EP4; /* ep4 [00:1000] */ - break; - case 1: /* Audio */ - ep_mask = ENABLE_EP3; /* ep3 [00:0100] */ - break; - case 2: /* Vbi */ - ep_mask = ENABLE_EP5; /* ep5 [01:0000] */ - break; - case 3: /* Sliced_cc */ - ep_mask = ENABLE_EP6; /* ep6 [10:0000] */ - break; - case 4: /* ts1 */ - case 6: /* ts1 parallel mode */ - ep_mask = ENABLE_EP1; /* ep1 [00:0001] */ - break; - case 5: /* ts2 */ - ep_mask = ENABLE_EP2; /* ep2 [00:0010] */ - break; - } - } if (start) { diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 8ed460d692e0..02d4d36735d3 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -1023,7 +1023,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, int nr = 0, ifnum; int i, isoc_pipe = 0; char *speed; - char descr[255] = ""; struct usb_interface_assoc_descriptor *assoc_desc; udev = usb_get_dev(interface_to_usbdev(interface)); @@ -1098,20 +1097,10 @@ static int cx231xx_usb_probe(struct usb_interface *interface, speed = "unknown"; } - if (udev->manufacturer) - strlcpy(descr, udev->manufacturer, sizeof(descr)); - - if (udev->product) { - if (*descr) - strlcat(descr, " ", sizeof(descr)); - strlcat(descr, udev->product, sizeof(descr)); - } - if (*descr) - strlcat(descr, " ", sizeof(descr)); - - cx231xx_info("New device %s@ %s Mbps " + cx231xx_info("New device %s %s @ %s Mbps " "(%04x:%04x) with %d interfaces\n", - descr, + udev->manufacturer ? udev->manufacturer : "", + udev->product ? udev->product : "", speed, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), diff --git a/drivers/media/video/cx231xx/cx231xx-i2c.c b/drivers/media/video/cx231xx/cx231xx-i2c.c index 925f3a04e53c..781feed406f7 100644 --- a/drivers/media/video/cx231xx/cx231xx-i2c.c +++ b/drivers/media/video/cx231xx/cx231xx-i2c.c @@ -499,16 +499,12 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus) BUG_ON(!dev->cx231xx_send_usb_command); - memcpy(&bus->i2c_adap, &cx231xx_adap_template, sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx231xx_algo, sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx231xx_client_template, - sizeof(bus->i2c_client)); - + bus->i2c_adap = cx231xx_adap_template; + bus->i2c_client = cx231xx_client_template; bus->i2c_adap.dev.parent = &dev->udev->dev; strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); - bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c index 3d15314e1f88..ac7db52f404f 100644 --- a/drivers/media/video/cx231xx/cx231xx-vbi.c +++ b/drivers/media/video/cx231xx/cx231xx-vbi.c @@ -448,7 +448,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, return -ENOMEM; } dev->vbi_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + urb->transfer_flags = 0; dev->vbi_mode.bulk_ctl.transfer_buffer[i] = kzalloc(sb_size, GFP_KERNEL); diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index e17447554a0d..a89d020de948 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -26,7 +26,6 @@ #include <linux/types.h> #include <linux/ioctl.h> #include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> #include <linux/workqueue.h> #include <linux/mutex.h> @@ -481,7 +480,6 @@ struct cx231xx_i2c { /* i2c i/o */ struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; struct i2c_client i2c_client; u32 i2c_rc; diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 13739e002a63..080e11157e5f 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -127,22 +127,37 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1250] = { .name = "Hauppauge WinTV-HVR1250", + .porta = CX23885_ANALOG_VIDEO, .portc = CX23885_MPEG_DVB, +#ifdef MT2131_NO_ANALOG_SUPPORT_YET + .tuner_type = TUNER_PHILIPS_TDA8290, + .tuner_addr = 0x42, /* 0x84 >> 1 */ + .tuner_bus = 1, +#endif + .force_bff = 1, .input = {{ +#ifdef MT2131_NO_ANALOG_SUPPORT_YET .type = CX23885_VMUX_TELEVISION, - .vmux = 0, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1, + .amux = CX25840_AUDIO8, .gpio0 = 0xff00, }, { - .type = CX23885_VMUX_DEBUG, - .vmux = 0, - .gpio0 = 0xff01, - }, { +#endif .type = CX23885_VMUX_COMPOSITE1, - .vmux = 1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, .gpio0 = 0xff02, }, { .type = CX23885_VMUX_SVIDEO, - .vmux = 2, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, .gpio0 = 0xff02, } }, }, @@ -267,7 +282,55 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1255] = { .name = "Hauppauge WinTV-HVR1255", + .porta = CX23885_ANALOG_VIDEO, + .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x42, /* 0x84 >> 1 */ + .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1 | + CX25840_DIF_ON, + .amux = CX25840_AUDIO8, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + } }, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1255_22111] = { + .name = "Hauppauge WinTV-HVR1255", + .porta = CX23885_ANALOG_VIDEO, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x42, /* 0x84 >> 1 */ + .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1 | + CX25840_DIF_ON, + .amux = CX25840_AUDIO8, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + } }, }, [CX23885_BOARD_HAUPPAUGE_HVR1210] = { .name = "Hauppauge WinTV-HVR1210", @@ -624,7 +687,7 @@ struct cx23885_subid cx23885_subids[] = { }, { .subvendor = 0x0070, .subdevice = 0x2259, - .card = CX23885_BOARD_HAUPPAUGE_HVR1255, + .card = CX23885_BOARD_HAUPPAUGE_HVR1255_22111, }, { .subvendor = 0x0070, .subdevice = 0x2291, @@ -900,7 +963,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) struct cx23885_dev *dev = port->dev; u32 bitmask = 0; - if (command == XC2028_RESET_CLK) + if ((command == XC2028_RESET_CLK) || (command == XC2028_I2C_FLUSH)) return 0; if (command != 0) { @@ -1130,6 +1193,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: 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 */ @@ -1267,6 +1331,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1400: case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: case CX23885_BOARD_HAUPPAUGE_HVR1210: /* FIXME: Implement me */ break; @@ -1424,6 +1489,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: case CX23885_BOARD_HAUPPAUGE_HVR1210: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: @@ -1511,6 +1577,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: case CX23885_BOARD_HAUPPAUGE_HVR1210: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_HAUPPAUGE_HVR1290: @@ -1526,10 +1593,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) */ switch (dev->board) { case CX23885_BOARD_TEVII_S470: - case CX23885_BOARD_HAUPPAUGE_HVR1250: /* Currently only enabled for the integrated IR controller */ if (!enable_885_ir) break; + case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1700: @@ -1539,6 +1606,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_MYGICA_X8506: diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index a80a92c47455..cd542684ba02 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -712,6 +712,7 @@ static int dvb_register(struct cx23885_tsport *port) } break; case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: i2c_bus = &dev->i2c_bus[0]; fe0->dvb.frontend = dvb_attach(s5h1411_attach, &hcw_s5h1411_config, @@ -721,6 +722,11 @@ static int dvb_register(struct cx23885_tsport *port) 0x60, &dev->i2c_bus[1].i2c_adap, &hauppauge_tda18271_config); } + + tda18271_attach(&dev->ts1.analog_fe, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + break; case CX23885_BOARD_HAUPPAUGE_HVR1800: i2c_bus = &dev->i2c_bus[0]; diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index be1e21d8295c..4887314339cb 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -316,19 +316,13 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); - memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template, - sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template, - sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx23885_i2c_client_template, - sizeof(bus->i2c_client)); - + bus->i2c_adap = cx23885_i2c_adap_template; + bus->i2c_client = cx23885_i2c_client_template; bus->i2c_adap.dev.parent = &dev->pci->dev; strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); - bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index c654bdc7ccb2..22f8e7fbd665 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -505,6 +505,9 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || (dev->board == CX23885_BOARD_MPX885) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, @@ -1578,7 +1581,9 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, fe = vfe->dvb.frontend; - if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) + if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111)) fe = &dev->ts1.analog_fe; if (fe && fe->ops.tuner_ops.set_analog_params) { @@ -1608,6 +1613,8 @@ int cx23885_set_frequency(struct file *file, void *priv, int ret; switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1255: + case CX23885_BOARD_HAUPPAUGE_HVR1255_22111: case CX23885_BOARD_HAUPPAUGE_HVR1850: ret = cx23885_set_freq_via_ops(dev, f); break; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index d884784a1c85..5d560c747e09 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -21,7 +21,6 @@ #include <linux/pci.h> #include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> #include <linux/kdev_t.h> #include <linux/slab.h> @@ -90,6 +89,7 @@ #define CX23885_BOARD_MYGICA_X8507 33 #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34 #define CX23885_BOARD_TEVII_S471 35 +#define CX23885_BOARD_HAUPPAUGE_HVR1255_22111 36 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 @@ -246,7 +246,6 @@ struct cx23885_i2c { /* i2c i/o */ struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; struct i2c_client i2c_client; u32 i2c_rc; diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c index 83c1aa6b2e6c..f11f6f07e915 100644 --- a/drivers/media/video/cx25821/cx25821-core.c +++ b/drivers/media/video/cx25821/cx25821-core.c @@ -904,9 +904,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) list_add_tail(&dev->devlist, &cx25821_devlist); mutex_unlock(&cx25821_devlist_mutex); - strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown"); - strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821"); - if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); diff --git a/drivers/media/video/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c index 6311180f430c..9844549764c9 100644 --- a/drivers/media/video/cx25821/cx25821-i2c.c +++ b/drivers/media/video/cx25821/cx25821-i2c.c @@ -305,18 +305,12 @@ int cx25821_i2c_register(struct cx25821_i2c *bus) dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); - memcpy(&bus->i2c_adap, &cx25821_i2c_adap_template, - sizeof(bus->i2c_adap)); - memcpy(&bus->i2c_algo, &cx25821_i2c_algo_template, - sizeof(bus->i2c_algo)); - memcpy(&bus->i2c_client, &cx25821_i2c_client_template, - sizeof(bus->i2c_client)); - + bus->i2c_adap = cx25821_i2c_adap_template; + bus->i2c_client = cx25821_i2c_client_template; bus->i2c_adap.dev.parent = &dev->pci->dev; strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); - bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c index 313fb20a0b47..6a92e5c70c2a 100644 --- a/drivers/media/video/cx25821/cx25821-medusa-video.c +++ b/drivers/media/video/cx25821/cx25821-medusa-video.c @@ -499,7 +499,7 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, mutex_lock(&dev->lock); /* no support */ - if (decoder < VDEC_A && decoder > VDEC_H) { + if (decoder < VDEC_A || decoder > VDEC_H) { mutex_unlock(&dev->lock); return; } diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h index b9aa801b00a7..8a9c0c869412 100644 --- a/drivers/media/video/cx25821/cx25821.h +++ b/drivers/media/video/cx25821/cx25821.h @@ -26,7 +26,6 @@ #include <linux/pci.h> #include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/sched.h> @@ -187,7 +186,7 @@ enum port { }; struct cx25821_board { - char *name; + const char *name; enum port porta; enum port portb; enum port portc; @@ -213,7 +212,6 @@ struct cx25821_i2c { /* i2c i/o */ struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; struct i2c_client i2c_client; u32 i2c_rc; diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index fc1ff69cffd0..d8eac3e30a7e 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -84,7 +84,7 @@ MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); /* ----------------------------------------------------------------------- */ -static void cx23885_std_setup(struct i2c_client *client); +static void cx23888_std_setup(struct i2c_client *client); int cx25840_write(struct i2c_client *client, u16 addr, u8 value) { @@ -638,10 +638,13 @@ static void cx23885_initialize(struct i2c_client *client) finish_wait(&state->fw_wait, &wait); destroy_workqueue(q); - /* Call the cx23885 specific std setup func, we no longer rely on + /* Call the cx23888 specific std setup func, we no longer rely on * the generic cx24840 func. */ - cx23885_std_setup(client); + if (is_cx23888(state)) + cx23888_std_setup(client); + else + cx25840_std_setup(client); /* (re)set input */ set_input(client, state->vid_input, state->aud_input); @@ -1103,9 +1106,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write4(client, 0x410, 0xffff0dbf); cx25840_write4(client, 0x414, 0x00137d03); - cx25840_write4(client, 0x418, 0x01008080); + + /* on the 887, 0x418 is HSCALE_CTRL, on the 888 it is + CHROMA_CTRL */ + if (is_cx23888(state)) + cx25840_write4(client, 0x418, 0x01008080); + else + cx25840_write4(client, 0x418, 0x01000000); + cx25840_write4(client, 0x41c, 0x00000000); - cx25840_write4(client, 0x420, 0x001c3e0f); + + /* on the 887, 0x420 is CHROMA_CTRL, on the 888 it is + CRUSH_CTRL */ + if (is_cx23888(state)) + cx25840_write4(client, 0x420, 0x001c3e0f); + else + cx25840_write4(client, 0x420, 0x001c8282); + cx25840_write4(client, 0x42c, 0x42600000); cx25840_write4(client, 0x430, 0x0000039b); cx25840_write4(client, 0x438, 0x00000000); @@ -1233,7 +1250,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write4(client, 0x8d0, 0x1f063870); } - if (is_cx2388x(state)) { + if (is_cx23888(state)) { /* HVR1850 */ /* AUD_IO_CTRL - I2S Input, Parallel1*/ /* - Channel 1 src - Parallel1 (Merlin out) */ @@ -1298,8 +1315,8 @@ static int set_v4lstd(struct i2c_client *client) } cx25840_and_or(client, 0x400, ~0xf, fmt); cx25840_and_or(client, 0x403, ~0x3, pal_m); - if (is_cx2388x(state)) - cx23885_std_setup(client); + if (is_cx23888(state)) + cx23888_std_setup(client); else cx25840_std_setup(client); if (!is_cx2583x(state)) @@ -1312,6 +1329,7 @@ static int set_v4lstd(struct i2c_client *client) static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); + struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); switch (ctrl->id) { @@ -1324,12 +1342,20 @@ static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_SATURATION: - cx25840_write(client, 0x420, ctrl->val << 1); - cx25840_write(client, 0x421, ctrl->val << 1); + if (is_cx23888(state)) { + cx25840_write(client, 0x418, ctrl->val << 1); + cx25840_write(client, 0x419, ctrl->val << 1); + } else { + cx25840_write(client, 0x420, ctrl->val << 1); + cx25840_write(client, 0x421, ctrl->val << 1); + } break; case V4L2_CID_HUE: - cx25840_write(client, 0x422, ctrl->val); + if (is_cx23888(state)) + cx25840_write(client, 0x41a, ctrl->val); + else + cx25840_write(client, 0x422, ctrl->val); break; default: @@ -1354,11 +1380,21 @@ static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt fmt->field = V4L2_FIELD_INTERLACED; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; - Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; + if (is_cx23888(state)) { + Vsrc = (cx25840_read(client, 0x42a) & 0x3f) << 4; + Vsrc |= (cx25840_read(client, 0x429) & 0xf0) >> 4; + } else { + Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; + Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; + } - Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; - Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; + if (is_cx23888(state)) { + Hsrc = (cx25840_read(client, 0x426) & 0x3f) << 4; + Hsrc |= (cx25840_read(client, 0x425) & 0xf0) >> 4; + } else { + Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; + Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; + } Vlines = fmt->height + (is_50Hz ? 4 : 7); @@ -1782,8 +1818,8 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd, struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (is_cx2388x(state)) - cx23885_std_setup(client); + if (is_cx23888(state)) + cx23888_std_setup(client); return set_input(client, input, state->aud_input); } @@ -1794,8 +1830,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd, struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (is_cx2388x(state)) - cx23885_std_setup(client); + if (is_cx23888(state)) + cx23888_std_setup(client); return set_input(client, state->vid_input, input); } @@ -4939,7 +4975,7 @@ void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) } } -static void cx23885_std_setup(struct i2c_client *client) +static void cx23888_std_setup(struct i2c_client *client) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); v4l2_std_id std = state->std; diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 04bf6627d362..dfac6e34859f 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -585,13 +585,10 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; int left = value->value.integer.value[0]; int right = value->value.integer.value[1]; int v, b; - memset(&client_ctl, 0, sizeof(client_ctl)); - /* Pass volume & balance onto any WM8775 */ if (left >= right) { v = left << 10; @@ -600,13 +597,8 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, v = right << 10; b = right ? 0xffff - (0x8000 * left) / right : 0x8000; } - client_ctl.value = v; - client_ctl.id = V4L2_CID_AUDIO_VOLUME; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - - client_ctl.value = b; - client_ctl.id = V4L2_CID_AUDIO_BALANCE; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); + wm8775_s_ctrl(core, V4L2_CID_AUDIO_VOLUME, v); + wm8775_s_ctrl(core, V4L2_CID_AUDIO_BALANCE, b); } /* OK - TODO: test it */ @@ -687,14 +679,8 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); /* Pass mute onto any WM8775 */ if ((core->board.audio_chip == V4L2_IDENT_WM8775) && - ((1<<6) == bit)) { - struct v4l2_control client_ctl; - - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.value = 0 != (vol & bit); - client_ctl.id = V4L2_CID_AUDIO_MUTE; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - } + ((1<<6) == bit)) + wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit)); ret = 1; } spin_unlock_irq(&chip->reg_lock); @@ -724,13 +710,10 @@ static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; - - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; - call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl); - value->value.integer.value[0] = client_ctl.value ? 1 : 0; + s32 val; + val = wm8775_g_ctrl(core, V4L2_CID_AUDIO_LOUDNESS); + value->value.integer.value[0] = val ? 1 : 0; return 0; } diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index ed7b2aa1ed83..843ffd9e533b 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -35,6 +35,7 @@ #include <linux/firmware.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include <media/cx2341x.h> #include "cx88.h" @@ -523,11 +524,10 @@ static void blackbird_codec_settings(struct cx8802_dev *dev) blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, dev->height, dev->width); - dev->params.width = dev->width; - dev->params.height = dev->height; - dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0; - - cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params); + dev->cxhdl.width = dev->width; + dev->cxhdl.height = dev->height; + cx2341x_handler_set_50hz(&dev->cxhdl, dev->core->tvnorm & V4L2_STD_625_50); + cx2341x_handler_setup(&dev->cxhdl); } static int blackbird_initialize_codec(struct cx8802_dev *dev) @@ -618,6 +618,8 @@ static int blackbird_start_codec(struct file *file, void *priv) /* initialize the video input */ blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); + cx2341x_handler_set_busy(&dev->cxhdl, 1); + /* start capturing to the host interface */ blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, BLACKBIRD_MPEG_CAPTURE, @@ -636,6 +638,8 @@ static int blackbird_stop_codec(struct cx8802_dev *dev) BLACKBIRD_RAW_BITS_NONE ); + cx2341x_handler_set_busy(&dev->cxhdl, 0); + dev->mpeg_active = 0; return 0; } @@ -685,58 +689,15 @@ static struct videobuf_queue_ops blackbird_qops = { /* ------------------------------------------------------------------ */ -static const u32 *ctrl_classes[] = { - cx88_user_ctrls, - cx2341x_mpeg_ctrls, - NULL -}; - -static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - /* Standard V4L2 controls */ - if (cx8800_ctrl_query(dev->core, qctrl) == 0) - return 0; - - /* MPEG V4L2 controls */ - if (cx2341x_ctrl_query(&dev->params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; -} - -/* ------------------------------------------------------------------ */ -/* IOCTL Handlers */ - -static int vidioc_querymenu (struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - blackbird_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&dev->params, qmenu->id)); -} - -static int vidioc_querycap (struct file *file, void *priv, +static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; struct cx88_core *core = dev->core; strcpy(cap->driver, "cx88_blackbird"); - strlcpy(cap->card, core->board.name, sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - if (UNSET != core->board.tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cx88_querycap(file, core, cap); return 0; } @@ -748,6 +709,7 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, strlcpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; + f->flags = V4L2_FMT_FLAG_COMPRESSED; return 0; } @@ -759,12 +721,12 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */ - f->fmt.pix.colorspace = 0; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; f->fmt.pix.field = fh->mpegq.field; - dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", dev->width, dev->height, fh->mpegq.field ); return 0; } @@ -777,9 +739,9 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; - f->fmt.pix.colorspace = 0; - dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", dev->width, dev->height, fh->mpegq.field ); return 0; } @@ -793,15 +755,15 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; - f->fmt.pix.colorspace = 0; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; fh->mpegq.field = f->fmt.pix.field; cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, f->fmt.pix.height, f->fmt.pix.width); - dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", + dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field ); return 0; } @@ -834,60 +796,21 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx8802_fh *fh = priv; + struct cx8802_dev *dev = fh->dev; + + if (!dev->mpeg_active) + blackbird_start_codec(file, fh); return videobuf_streamon(&fh->mpegq); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx8802_fh *fh = priv; - return videobuf_streamoff(&fh->mpegq); -} - -static int vidioc_g_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS); -} - -static int vidioc_s_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; + struct cx8802_dev *dev = fh->dev; if (dev->mpeg_active) blackbird_stop_codec(dev); - - p = dev->params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); - if (!err) { - err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); - dev->params = p; - } - return err; -} - -static int vidioc_try_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - p = dev->params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - - return err; + return videobuf_streamoff(&fh->mpegq); } static int vidioc_s_frequency (struct file *file, void *priv, @@ -897,6 +820,10 @@ static int vidioc_s_frequency (struct file *file, void *priv, struct cx8802_dev *dev = fh->dev; struct cx88_core *core = dev->core; + if (unlikely(UNSET == core->board.tuner_type)) + return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; if (dev->mpeg_active) blackbird_stop_codec(dev); @@ -914,29 +841,11 @@ static int vidioc_log_status (struct file *file, void *priv) char name[32 + 2]; snprintf(name, sizeof(name), "%s/2", core->name); - printk("%s/2: ============ START LOG STATUS ============\n", - core->name); call_all(core, core, log_status); - cx2341x_log_status(&dev->params, name); - printk("%s/2: ============= END LOG STATUS =============\n", - core->name); + v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name); return 0; } -static int vidioc_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - - if (blackbird_queryctrl(dev, qctrl) == 0) - return 0; - - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx8800_ctrl_query(dev->core, qctrl); -} - static int vidioc_enum_input (struct file *file, void *priv, struct v4l2_input *i) { @@ -944,22 +853,6 @@ static int vidioc_enum_input (struct file *file, void *priv, return cx88_enum_input (core,i); } -static int vidioc_g_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - return - cx88_get_control(core,ctl); -} - -static int vidioc_s_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; - return - cx88_set_control(core,ctl); -} - static int vidioc_g_frequency (struct file *file, void *priv, struct v4l2_frequency *f) { @@ -968,8 +861,9 @@ static int vidioc_g_frequency (struct file *file, void *priv, if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; - f->type = V4L2_TUNER_ANALOG_TV; f->frequency = core->freq; call_all(core, tuner, g_frequency, f); @@ -990,6 +884,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) if (i >= 4) return -EINVAL; + if (0 == INPUT(i).type) + return -EINVAL; mutex_lock(&core->lock); cx88_newstation(core); @@ -1010,9 +906,9 @@ static int vidioc_g_tuner (struct file *file, void *priv, return -EINVAL; strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; + call_all(core, tuner, g_tuner, t); cx88_get_stereo(core ,t); reg = cx_read(MO_DEVICE_STATUS); @@ -1034,6 +930,14 @@ static int vidioc_s_tuner (struct file *file, void *priv, return 0; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + + *tvnorm = core->tvnorm; + return 0; +} + static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; @@ -1087,6 +991,7 @@ static int mpeg_open(struct file *file) mutex_unlock(&dev->core->lock); return -ENOMEM; } + v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; fh->dev = dev; @@ -1103,6 +1008,7 @@ static int mpeg_open(struct file *file) dev->core->mpeg_users++; mutex_unlock(&dev->core->lock); + v4l2_fh_add(&fh->fh); return 0; } @@ -1123,6 +1029,8 @@ static int mpeg_release(struct file *file) videobuf_mmap_free(&fh->mpegq); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); @@ -1155,13 +1063,14 @@ mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) static unsigned int mpeg_poll(struct file *file, struct poll_table_struct *wait) { + unsigned long req_events = poll_requested_events(wait); struct cx8802_fh *fh = file->private_data; struct cx8802_dev *dev = fh->dev; - if (!dev->mpeg_active) + if (!dev->mpeg_active && (req_events & (POLLIN | POLLRDNORM))) blackbird_start_codec(file, fh); - return videobuf_poll_stream(file, &fh->mpegq, wait); + return v4l2_ctrl_poll(file, wait) | videobuf_poll_stream(file, &fh->mpegq, wait); } static int @@ -1180,11 +1089,10 @@ static const struct v4l2_file_operations mpeg_fops = .read = mpeg_read, .poll = mpeg_poll, .mmap = mpeg_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { - .vidioc_querymenu = vidioc_querymenu, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1196,21 +1104,18 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_dqbuf = vidioc_dqbuf, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, .vidioc_s_frequency = vidioc_s_frequency, .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device cx8802_mpeg_template = { @@ -1218,7 +1123,6 @@ static struct video_device cx8802_mpeg_template = { .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, }; /* ------------------------------------------------------------------ */ @@ -1286,6 +1190,7 @@ static int blackbird_register_video(struct cx8802_dev *dev) dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci, &cx8802_mpeg_template,"mpeg"); + dev->mpeg_dev->ctrl_handler = &dev->cxhdl.hdl; video_set_drvdata(dev->mpeg_dev, dev); err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1); if (err < 0) { @@ -1318,17 +1223,20 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) goto fail_core; dev->width = 720; - dev->height = 576; - cx2341x_fill_defaults(&dev->params); - dev->params.port = CX2341X_PORT_STREAMING; - - cx8802_mpeg_template.current_norm = core->tvnorm; - if (core->tvnorm & V4L2_STD_525_60) { dev->height = 480; } else { dev->height = 576; } + dev->cxhdl.port = CX2341X_PORT_STREAMING; + dev->cxhdl.width = dev->width; + dev->cxhdl.height = dev->height; + dev->cxhdl.func = blackbird_mbox_func; + dev->cxhdl.priv = dev; + err = cx2341x_handler_init(&dev->cxhdl, 36); + if (err) + goto fail_core; + v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl); /* blackbird stuff */ printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", @@ -1336,12 +1244,14 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) host_setup(dev->core); blackbird_initialize_codec(dev); - blackbird_register_video(dev); /* initial device configuration: needed ? */ // init_controls(core); cx88_set_tvnorm(core,core->tvnorm); cx88_video_mux(core,0); + cx2341x_handler_set_50hz(&dev->cxhdl, dev->height == 576); + cx2341x_handler_setup(&dev->cxhdl); + blackbird_register_video(dev); return 0; @@ -1351,8 +1261,12 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) static int cx8802_blackbird_remove(struct cx8802_driver *drv) { + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = core->dvbdev; + /* blackbird */ blackbird_unregister_video(drv->core->dvbdev); + v4l2_ctrl_handler_free(&dev->cxhdl.hdl); return 0; } diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index cbd5d119a2c6..4e9d4f722960 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -3693,7 +3693,22 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) return NULL; } + if (v4l2_ctrl_handler_init(&core->video_hdl, 13)) { + v4l2_device_unregister(&core->v4l2_dev); + kfree(core); + return NULL; + } + + if (v4l2_ctrl_handler_init(&core->audio_hdl, 13)) { + v4l2_ctrl_handler_free(&core->video_hdl); + v4l2_device_unregister(&core->v4l2_dev); + kfree(core); + return NULL; + } + if (0 != cx88_get_resources(core, pci)) { + v4l2_ctrl_handler_free(&core->video_hdl); + v4l2_ctrl_handler_free(&core->audio_hdl); v4l2_device_unregister(&core->v4l2_dev); kfree(core); return NULL; @@ -3706,6 +3721,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) core->bmmio = (u8 __iomem *)core->lmmio; if (core->lmmio == NULL) { + release_mem_region(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + v4l2_ctrl_handler_free(&core->video_hdl); + v4l2_ctrl_handler_free(&core->audio_hdl); + v4l2_device_unregister(&core->v4l2_dev); kfree(core); return NULL; } diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index fbfdd8067937..e81c735f012a 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1012,6 +1012,9 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) // tell i2c chips call_all(core, core, s_std, norm); + /* The chroma_agc control should be inaccessible if the video format is SECAM */ + v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM); + // done return 0; } @@ -1030,10 +1033,10 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, return NULL; *vfd = *template_; vfd->v4l2_dev = &core->v4l2_dev; - vfd->parent = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", core->name, type, core->board.name); + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); return vfd; } @@ -1086,6 +1089,8 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) iounmap(core->lmmio); cx88_devcount--; mutex_unlock(&devlist); + v4l2_ctrl_handler_free(&core->video_hdl); + v4l2_ctrl_handler_free(&core->audio_hdl); v4l2_device_unregister(&core->v4l2_dev); kfree(core); } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 921c56d115d6..f6fcc7e763ab 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -40,6 +40,7 @@ #include "cx88.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include <media/wm8775.h> MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); @@ -155,219 +156,147 @@ static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) /* ------------------------------------------------------------------- */ -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, +struct cx88_ctrl { + /* control information */ + u32 id; + s32 minimum; + s32 maximum; + u32 step; + s32 default_value; + + /* control register information */ + u32 off; + u32 reg; + u32 sreg; + u32 mask; + u32 shift; }; -static const struct cx88_ctrl cx8800_ctls[] = { +static const struct cx88_ctrl cx8800_vid_ctls[] = { /* --- video --- */ { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = MO_CONTR_BRIGHT, - .mask = 0x00ff, - .shift = 0, + .id = V4L2_CID_BRIGHTNESS, + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .off = 128, + .reg = MO_CONTR_BRIGHT, + .mask = 0x00ff, + .shift = 0, },{ - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = MO_CONTR_BRIGHT, - .mask = 0xff00, - .shift = 8, + .id = V4L2_CID_CONTRAST, + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x3f, + .off = 0, + .reg = MO_CONTR_BRIGHT, + .mask = 0xff00, + .shift = 8, },{ - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = MO_HUE, - .mask = 0x00ff, - .shift = 0, + .id = V4L2_CID_HUE, + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .off = 128, + .reg = MO_HUE, + .mask = 0x00ff, + .shift = 0, },{ /* strictly, this only describes only U saturation. * V saturation is handled specially through code. */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = MO_UV_SATURATION, - .mask = 0x00ff, - .shift = 0, + .id = V4L2_CID_SATURATION, + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .off = 0, + .reg = MO_UV_SATURATION, + .mask = 0x00ff, + .shift = 0, }, { - .v = { - .id = V4L2_CID_SHARPNESS, - .name = "Sharpness", - .minimum = 0, - .maximum = 4, - .step = 1, - .default_value = 0x0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, + .id = V4L2_CID_SHARPNESS, + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0x0, + .off = 0, /* NOTE: the value is converted and written to both even and odd registers in the code */ - .reg = MO_FILTER_ODD, - .mask = 7 << 7, - .shift = 7, + .reg = MO_FILTER_ODD, + .mask = 7 << 7, + .shift = 7, }, { - .v = { - .id = V4L2_CID_CHROMA_AGC, - .name = "Chroma AGC", - .minimum = 0, - .maximum = 1, - .default_value = 0x1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = MO_INPUT_FORMAT, - .mask = 1 << 10, - .shift = 10, + .id = V4L2_CID_CHROMA_AGC, + .minimum = 0, + .maximum = 1, + .default_value = 0x1, + .reg = MO_INPUT_FORMAT, + .mask = 1 << 10, + .shift = 10, }, { - .v = { - .id = V4L2_CID_COLOR_KILLER, - .name = "Color killer", - .minimum = 0, - .maximum = 1, - .default_value = 0x1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = MO_INPUT_FORMAT, - .mask = 1 << 9, - .shift = 9, + .id = V4L2_CID_COLOR_KILLER, + .minimum = 0, + .maximum = 1, + .default_value = 0x1, + .reg = MO_INPUT_FORMAT, + .mask = 1 << 9, + .shift = 9, }, { - .v = { - .id = V4L2_CID_BAND_STOP_FILTER, - .name = "Notch filter", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0x0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = MO_HTOTAL, - .mask = 3 << 11, - .shift = 11, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = AUD_VOL_CTL, - .sreg = SHADOW_AUD_VOL_CTL, - .mask = (1 << 6), - .shift = 6, + .id = V4L2_CID_BAND_STOP_FILTER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0x0, + .off = 0, + .reg = MO_HTOTAL, + .mask = 3 << 11, + .shift = 11, + } +}; + +static const struct cx88_ctrl cx8800_aud_ctls[] = { + { + /* --- audio --- */ + .id = V4L2_CID_AUDIO_MUTE, + .minimum = 0, + .maximum = 1, + .default_value = 1, + .reg = AUD_VOL_CTL, + .sreg = SHADOW_AUD_VOL_CTL, + .mask = (1 << 6), + .shift = 6, },{ - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = AUD_VOL_CTL, - .sreg = SHADOW_AUD_VOL_CTL, - .mask = 0x3f, - .shift = 0, + .id = V4L2_CID_AUDIO_VOLUME, + .minimum = 0, + .maximum = 0x3f, + .step = 1, + .default_value = 0x3f, + .reg = AUD_VOL_CTL, + .sreg = SHADOW_AUD_VOL_CTL, + .mask = 0x3f, + .shift = 0, },{ - .v = { - .id = V4L2_CID_AUDIO_BALANCE, - .name = "Balance", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x40, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = AUD_BAL_CTL, - .sreg = SHADOW_AUD_BAL_CTL, - .mask = 0x7f, - .shift = 0, + .id = V4L2_CID_AUDIO_BALANCE, + .minimum = 0, + .maximum = 0x7f, + .step = 1, + .default_value = 0x40, + .reg = AUD_BAL_CTL, + .sreg = SHADOW_AUD_BAL_CTL, + .mask = 0x7f, + .shift = 0, } }; -enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) }; - -/* Must be sorted from low to high control ID! */ -const u32 cx88_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_BALANCE, - V4L2_CID_AUDIO_MUTE, - V4L2_CID_SHARPNESS, - V4L2_CID_CHROMA_AGC, - V4L2_CID_COLOR_KILLER, - V4L2_CID_BAND_STOP_FILTER, - 0 -}; -EXPORT_SYMBOL(cx88_user_ctrls); -static const u32 * const ctrl_classes[] = { - cx88_user_ctrls, - NULL +enum { + CX8800_VID_CTLS = ARRAY_SIZE(cx8800_vid_ctls), + CX8800_AUD_CTLS = ARRAY_SIZE(cx8800_aud_ctls), }; -int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || - qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX8800_CTLS; i++) - if (cx8800_ctls[i].v.id == qctrl->id) - break; - if (i == CX8800_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx8800_ctls[i].v; - /* Report chroma AGC as inactive when SECAM is selected */ - if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC && - core->tvnorm & V4L2_STD_SECAM) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - - return 0; -} -EXPORT_SYMBOL(cx8800_ctrl_query); - /* ------------------------------------------------------------------- */ /* resource management */ @@ -591,8 +520,9 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { struct cx8800_fh *fh = q->priv_data; + struct cx8800_dev *dev = fh->dev; - *size = fh->fmt->depth*fh->width*fh->height >> 3; + *size = dev->fmt->depth * dev->width * dev->height >> 3; if (0 == *count) *count = 32; if (*size * *count > vid_limit * 1024 * 1024) @@ -611,21 +541,21 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc, init_buffer = 0; - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) + BUG_ON(NULL == dev->fmt); + if (dev->width < 48 || dev->width > norm_maxw(core->tvnorm) || + dev->height < 32 || dev->height > norm_maxh(core->tvnorm)) return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || + if (buf->fmt != dev->fmt || + buf->vb.width != dev->width || + buf->vb.height != dev->height || buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; + buf->fmt = dev->fmt; + buf->vb.width = dev->width; + buf->vb.height = dev->height; buf->vb.field = field; init_buffer = 1; } @@ -675,7 +605,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", buf, buf->vb.i, - fh->width, fh->height, fh->fmt->depth, fh->fmt->name, + dev->width, dev->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); buf->vb.state = VIDEOBUF_PREPARED; @@ -755,12 +685,15 @@ static const struct videobuf_queue_ops cx8800_video_qops = { /* ------------------------------------------------------------------ */ -static struct videobuf_queue* get_queue(struct cx8800_fh *fh) +static struct videobuf_queue *get_queue(struct file *file) { - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + struct video_device *vdev = video_devdata(file); + struct cx8800_fh *fh = file->private_data; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: return &fh->vidq; - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: return &fh->vbiq; default: BUG(); @@ -768,12 +701,14 @@ static struct videobuf_queue* get_queue(struct cx8800_fh *fh) } } -static int get_ressource(struct cx8800_fh *fh) +static int get_resource(struct file *file) { - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + struct video_device *vdev = video_devdata(file); + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: return RESOURCE_VBI; default: BUG(); @@ -810,13 +745,9 @@ static int video_open(struct file *file) if (unlikely(!fh)) return -ENOMEM; + v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; fh->dev = dev; - fh->radio = radio; - fh->type = type; - fh->width = 320; - fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); mutex_lock(&core->lock); @@ -833,7 +764,7 @@ static int video_open(struct file *file) sizeof(struct cx88_buffer), fh, NULL); - if (fh->radio) { + if (vdev->vfl_type == VFL_TYPE_RADIO) { dprintk(1,"video_open: setting radio device\n"); cx_write(MO_GP3_IO, core->board.radio.gpio3); cx_write(MO_GP0_IO, core->board.radio.gpio0); @@ -859,6 +790,7 @@ static int video_open(struct file *file) core->users++; mutex_unlock(&core->lock); + v4l2_fh_add(&fh->fh); return 0; } @@ -866,15 +798,16 @@ static int video_open(struct file *file) static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { + struct video_device *vdev = video_devdata(file); struct cx8800_fh *fh = file->private_data; - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: if (res_locked(fh->dev,RESOURCE_VIDEO)) return -EBUSY; return videobuf_read_one(&fh->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: if (!res_get(fh->dev,fh,RESOURCE_VBI)) return -EBUSY; return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, @@ -888,16 +821,16 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { + struct video_device *vdev = video_devdata(file); struct cx8800_fh *fh = file->private_data; struct cx88_buffer *buf; - unsigned int rc = POLLERR; + unsigned int rc = v4l2_ctrl_poll(file, wait); - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (vdev->vfl_type == VFL_TYPE_VBI) { if (!res_get(fh->dev,fh,RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbiq, wait); + return rc | POLLERR; + return rc | videobuf_poll_stream(file, &fh->vbiq, wait); } - mutex_lock(&fh->vidq.vb_lock); if (res_check(fh,RESOURCE_VIDEO)) { /* streaming capture */ @@ -913,9 +846,7 @@ video_poll(struct file *file, struct poll_table_struct *wait) poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; + rc |= POLLIN|POLLRDNORM; done: mutex_unlock(&fh->vidq.vb_lock); return rc; @@ -952,6 +883,8 @@ static int video_release(struct file *file) videobuf_mmap_free(&fh->vbiq); mutex_lock(&dev->core->lock); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); @@ -966,156 +899,104 @@ static int video_release(struct file *file) static int video_mmap(struct file *file, struct vm_area_struct * vma) { - struct cx8800_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); + return videobuf_mmap_mapper(get_queue(file), vma); } /* ------------------------------------------------------------------ */ /* VIDEO CTRL IOCTLS */ -int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) +static int cx8800_s_vid_ctrl(struct v4l2_ctrl *ctrl) { - const struct cx88_ctrl *c = NULL; - u32 value; - int i; + struct cx88_core *core = + container_of(ctrl->handler, struct cx88_core, video_hdl); + const struct cx88_ctrl *cc = ctrl->priv; + u32 value, mask; - for (i = 0; i < CX8800_CTLS; i++) - if (cx8800_ctls[i].v.id == ctl->id) - c = &cx8800_ctls[i]; - if (unlikely(NULL == c)) - return -EINVAL; + mask = cc->mask; + switch (ctrl->id) { + case V4L2_CID_SATURATION: + /* special v_sat handling */ - value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); - switch (ctl->id) { - case V4L2_CID_AUDIO_BALANCE: - ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) - : (0x7f - (value & 0x7f)); - break; - case V4L2_CID_AUDIO_VOLUME: - ctl->value = 0x3f - (value & 0x3f); + value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; + + if (core->tvnorm & V4L2_STD_SECAM) { + /* For SECAM, both U and V sat should be equal */ + value = value << 8 | value; + } else { + /* Keeps U Saturation proportional to V Sat */ + value = (value * 0x5a) / 0x7f << 8 | value; + } + mask = 0xffff; break; case V4L2_CID_SHARPNESS: - ctl->value = ((value & 0x0200) ? (((value & 0x0180) >> 7) + 1) - : 0); + /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ + value = (ctrl->val < 1 ? 0 : ((ctrl->val + 3) << 7)); + /* needs to be set for both fields */ + cx_andor(MO_FILTER_EVEN, mask, value); + break; + case V4L2_CID_CHROMA_AGC: + value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; default: - ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; + value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; } - dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctl->id, c->v.name, ctl->value, c->reg, - value,c->mask, c->sreg ? " [shadowed]" : ""); + dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctrl->id, ctrl->name, ctrl->val, cc->reg, value, + mask, cc->sreg ? " [shadowed]" : ""); + if (cc->sreg) + cx_sandor(cc->sreg, cc->reg, mask, value); + else + cx_andor(cc->reg, mask, value); return 0; } -EXPORT_SYMBOL(cx88_get_control); -int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) +static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) { - const struct cx88_ctrl *c = NULL; + struct cx88_core *core = + container_of(ctrl->handler, struct cx88_core, audio_hdl); + const struct cx88_ctrl *cc = ctrl->priv; u32 value,mask; - int i; - - for (i = 0; i < CX8800_CTLS; i++) { - if (cx8800_ctls[i].v.id == ctl->id) { - c = &cx8800_ctls[i]; - } - } - if (unlikely(NULL == c)) - return -EINVAL; - - if (ctl->value < c->v.minimum) - ctl->value = c->v.minimum; - if (ctl->value > c->v.maximum) - ctl->value = c->v.maximum; /* Pass changes onto any WM8775 */ if (core->board.audio_chip == V4L2_IDENT_WM8775) { - struct v4l2_control client_ctl; - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.id = ctl->id; - - switch (ctl->id) { + switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - client_ctl.value = ctl->value; + wm8775_s_ctrl(core, ctrl->id, ctrl->val); break; case V4L2_CID_AUDIO_VOLUME: - client_ctl.value = (ctl->value) ? - (0x90 + ctl->value) << 8 : 0; + wm8775_s_ctrl(core, ctrl->id, (ctrl->val) ? + (0x90 + ctrl->val) << 8 : 0); break; case V4L2_CID_AUDIO_BALANCE: - client_ctl.value = ctl->value << 9; + wm8775_s_ctrl(core, ctrl->id, ctrl->val << 9); break; default: - client_ctl.id = 0; break; } - if (client_ctl.id) - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); } - mask=c->mask; - switch (ctl->id) { + mask = cc->mask; + switch (ctrl->id) { case V4L2_CID_AUDIO_BALANCE: - value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); + value = (ctrl->val < 0x40) ? (0x7f - ctrl->val) : (ctrl->val - 0x40); break; case V4L2_CID_AUDIO_VOLUME: - value = 0x3f - (ctl->value & 0x3f); - break; - case V4L2_CID_SATURATION: - /* special v_sat handling */ - - value = ((ctl->value - c->off) << c->shift) & c->mask; - - if (core->tvnorm & V4L2_STD_SECAM) { - /* For SECAM, both U and V sat should be equal */ - value=value<<8|value; - } else { - /* Keeps U Saturation proportional to V Sat */ - value=(value*0x5a)/0x7f<<8|value; - } - mask=0xffff; - break; - case V4L2_CID_SHARPNESS: - /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ - value = (ctl->value < 1 ? 0 : ((ctl->value + 3) << 7)); - /* needs to be set for both fields */ - cx_andor(MO_FILTER_EVEN, mask, value); - break; - case V4L2_CID_CHROMA_AGC: - /* Do not allow chroma AGC to be enabled for SECAM */ - value = ((ctl->value - c->off) << c->shift) & c->mask; - if (core->tvnorm & V4L2_STD_SECAM && value) - return -EINVAL; + value = 0x3f - (ctrl->val & 0x3f); break; default: - value = ((ctl->value - c->off) << c->shift) & c->mask; + value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; } dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctl->id, c->v.name, ctl->value, c->reg, value, - mask, c->sreg ? " [shadowed]" : ""); - if (c->sreg) { - cx_sandor(c->sreg, c->reg, mask, value); - } else { - cx_andor(c->reg, mask, value); - } + ctrl->id, ctrl->name, ctrl->val, cc->reg, value, + mask, cc->sreg ? " [shadowed]" : ""); + if (cc->sreg) + cx_sandor(cc->sreg, cc->reg, mask, value); + else + cx_andor(cc->reg, mask, value); return 0; } -EXPORT_SYMBOL(cx88_set_control); - -static void init_controls(struct cx88_core *core) -{ - struct v4l2_control ctrl; - int i; - - for (i = 0; i < CX8800_CTLS; i++) { - ctrl.id=cx8800_ctls[i].v.id; - ctrl.value=cx8800_ctls[i].v.default_value; - - cx88_set_control(core, &ctrl); - } -} /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ @@ -1124,15 +1005,17 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; + (f->fmt.pix.width * dev->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } @@ -1184,33 +1067,54 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; int err = vidioc_try_fmt_vid_cap (file,priv,f); if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; fh->vidq.field = f->fmt.pix.field; return 0; } -static int vidioc_querycap (struct file *file, void *priv, +void cx88_querycap(struct file *file, struct cx88_core *core, + struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + + strlcpy(cap->card, core->board.name, sizeof(cap->card)); + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (UNSET != core->board.tuner_type) + cap->device_caps |= V4L2_CAP_TUNER; + switch (vdev->vfl_type) { + case VFL_TYPE_RADIO: + cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; + break; + case VFL_TYPE_GRABBER: + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + break; + } + cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; + if (core->board.radio.type == CX88_RADIO) + cap->capabilities |= V4L2_CAP_RADIO; +} +EXPORT_SYMBOL(cx88_querycap); + +static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, core->board.name, sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE; - if (UNSET != core->board.tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cx88_querycap(file, core, cap); return 0; } @@ -1228,69 +1132,67 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) { - struct cx8800_fh *fh = priv; - return (videobuf_reqbufs(get_queue(fh), p)); + return videobuf_reqbufs(get_queue(file), p); } static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx8800_fh *fh = priv; - return (videobuf_querybuf(get_queue(fh), p)); + return videobuf_querybuf(get_queue(file), p); } static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx8800_fh *fh = priv; - return (videobuf_qbuf(get_queue(fh), p)); + return videobuf_qbuf(get_queue(file), p); } static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx8800_fh *fh = priv; - return (videobuf_dqbuf(get_queue(fh), p, - file->f_flags & O_NONBLOCK)); + return videobuf_dqbuf(get_queue(file), p, + file->f_flags & O_NONBLOCK); } static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { + struct video_device *vdev = video_devdata(file); struct cx8800_fh *fh = priv; struct cx8800_dev *dev = fh->dev; - /* We should remember that this driver also supports teletext, */ - /* so we have to test if the v4l2_buf_type is VBI capture data. */ - if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))) - return -EINVAL; - - if (unlikely(i != fh->type)) + if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; - if (unlikely(!res_get(dev,fh,get_ressource(fh)))) + if (unlikely(!res_get(dev, fh, get_resource(file)))) return -EBUSY; - return videobuf_streamon(get_queue(fh)); + return videobuf_streamon(get_queue(file)); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { + struct video_device *vdev = video_devdata(file); struct cx8800_fh *fh = priv; struct cx8800_dev *dev = fh->dev; int err, res; - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) + if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; - if (i != fh->type) - return -EINVAL; - - res = get_ressource(fh); - err = videobuf_streamoff(get_queue(fh)); + res = get_resource(file); + err = videobuf_streamoff(get_queue(file)); if (err < 0) return err; res_free(dev,fh,res); return 0; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + *tvnorm = core->tvnorm; + return 0; +} + static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms) { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; @@ -1327,8 +1229,8 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) if ((CX88_VMUX_TELEVISION == INPUT(n).type) || (CX88_VMUX_CABLE == INPUT(n).type)) { i->type = V4L2_INPUT_TYPE_TUNER; - i->std = CX88_NORMS; } + i->std = CX88_NORMS; return 0; } EXPORT_SYMBOL(cx88_enum_input); @@ -1354,6 +1256,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) if (i >= 4) return -EINVAL; + if (0 == INPUT(i).type) + return -EINVAL; mutex_lock(&core->lock); cx88_newstation(core); @@ -1362,35 +1266,6 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) return 0; } - - -static int vidioc_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx8800_ctrl_query(core, qctrl); -} - -static int vidioc_g_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - return - cx88_get_control(core,ctl); -} - -static int vidioc_s_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; - return - cx88_set_control(core,ctl); -} - static int vidioc_g_tuner (struct file *file, void *priv, struct v4l2_tuner *t) { @@ -1403,9 +1278,9 @@ static int vidioc_g_tuner (struct file *file, void *priv, return -EINVAL; strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; + call_all(core, tuner, g_tuner, t); cx88_get_stereo(core ,t); reg = cx_read(MO_DEVICE_STATUS); @@ -1435,9 +1310,9 @@ static int vidioc_g_frequency (struct file *file, void *priv, if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; + if (f->tuner) + return -EINVAL; - /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = core->freq; call_all(core, tuner, g_frequency, f); @@ -1454,9 +1329,10 @@ int cx88_set_freq (struct cx88_core *core, return -EINVAL; mutex_lock(&core->lock); - core->freq = f->frequency; cx88_newstation(core); call_all(core, tuner, s_frequency, f); + call_all(core, tuner, g_frequency, f); + core->freq = f->frequency; /* When changing channels it is required to reset TVAUDIO */ msleep (10); @@ -1474,13 +1350,17 @@ static int vidioc_s_frequency (struct file *file, void *priv, struct cx8800_fh *fh = priv; struct cx88_core *core = fh->dev->core; - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; + return cx88_set_freq(core, f); +} - return - cx88_set_freq (core,f); +static int vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + if (!v4l2_chip_match_host(&chip->match)) + return -EINVAL; + chip->revision = 0; + chip->ident = V4L2_IDENT_UNKNOWN; + return 0; } #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -1513,19 +1393,6 @@ static int vidioc_s_register (struct file *file, void *fh, /* RADIO ESPECIFIC IOCTLS */ /* ----------------------------------------------------------- */ -static int radio_querycap (struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; - struct cx88_core *core = dev->core; - - strcpy(cap->driver, "cx8800"); - strlcpy(cap->card, core->board.name, sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - static int radio_g_tuner (struct file *file, void *priv, struct v4l2_tuner *t) { @@ -1535,32 +1402,11 @@ static int radio_g_tuner (struct file *file, void *priv, return -EINVAL; strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; call_all(core, tuner, g_tuner, t); return 0; } -static int radio_enum_input (struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strcpy(i->name,"Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name,"Radio"); - return 0; -} - /* FIXME: Should add a standard for radio */ static int radio_s_tuner (struct file *file, void *priv, @@ -1570,46 +1416,14 @@ static int radio_s_tuner (struct file *file, void *priv, if (0 != t->index) return -EINVAL; + if (t->audmode > V4L2_TUNER_MODE_STEREO) + t->audmode = V4L2_TUNER_MODE_STEREO; call_all(core, tuner, s_tuner, t); return 0; } -static int radio_s_audio (struct file *file, void *fh, - struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input (struct file *file, void *fh, unsigned int i) -{ - return 0; -} - -static int radio_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - int i; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE || - c->id == V4L2_CID_AUDIO_VOLUME || - c->id == V4L2_CID_AUDIO_BALANCE) { - for (i = 0; i < CX8800_CTLS; i++) { - if (cx8800_ctls[i].v.id == c->id) - break; - } - if (i == CX8800_CTLS) - return -EINVAL; - *c = cx8800_ctls[i].v; - } else - *c = no_ctl; - return 0; -} - /* ----------------------------------------------------------- */ static void cx8800_vid_timeout(unsigned long data) @@ -1752,63 +1566,89 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, - .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, - .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif }; -static struct video_device cx8800_vbi_template; - static const struct video_device cx8800_video_template = { .name = "cx8800-video", .fops = &video_fops, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, +}; + +static const struct v4l2_ioctl_ops vbi_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_chip_ident = vidioc_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +static const struct video_device cx8800_vbi_template = { + .name = "cx8800-vbi", + .fops = &video_fops, + .ioctl_ops = &vbi_ioctl_ops, + .tvnorms = CX88_NORMS, }; static const struct v4l2_file_operations radio_fops = { .owner = THIS_MODULE, .open = video_open, + .poll = v4l2_ctrl_poll, .release = video_release, .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, + .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, @@ -1821,6 +1661,14 @@ static const struct video_device cx8800_radio_template = { .ioctl_ops = &radio_ioctl_ops, }; +static const struct v4l2_ctrl_ops cx8800_ctrl_vid_ops = { + .s_ctrl = cx8800_s_vid_ctrl, +}; + +static const struct v4l2_ctrl_ops cx8800_ctrl_aud_ops = { + .s_ctrl = cx8800_s_aud_ctrl, +}; + /* ----------------------------------------------------------- */ static void cx8800_unregister_video(struct cx8800_dev *dev) @@ -1853,8 +1701,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, { struct cx8800_dev *dev; struct cx88_core *core; - int err; + int i; dev = kzalloc(sizeof(*dev),GFP_KERNEL); if (NULL == dev) @@ -1888,14 +1736,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, goto fail_core; } - /* Initialize VBI template */ - memcpy( &cx8800_vbi_template, &cx8800_video_template, - sizeof(cx8800_vbi_template) ); - strcpy(cx8800_vbi_template.name,"cx8800-vbi"); - /* initialize driver struct */ spin_lock_init(&dev->slock); - core->tvnorm = cx8800_video_template.current_norm; + core->tvnorm = V4L2_STD_NTSC_M; /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); @@ -1925,6 +1768,35 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, } cx_set(MO_PCI_INTMSK, core->pci_irqmask); + for (i = 0; i < CX8800_AUD_CTLS; i++) { + const struct cx88_ctrl *cc = &cx8800_aud_ctls[i]; + struct v4l2_ctrl *vc; + + vc = v4l2_ctrl_new_std(&core->audio_hdl, &cx8800_ctrl_aud_ops, + cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); + if (vc == NULL) { + err = core->audio_hdl.error; + goto fail_core; + } + vc->priv = (void *)cc; + } + + for (i = 0; i < CX8800_VID_CTLS; i++) { + const struct cx88_ctrl *cc = &cx8800_vid_ctls[i]; + struct v4l2_ctrl *vc; + + vc = v4l2_ctrl_new_std(&core->video_hdl, &cx8800_ctrl_vid_ops, + cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); + if (vc == NULL) { + err = core->video_hdl.error; + goto fail_core; + } + vc->priv = (void *)cc; + if (vc->id == V4L2_CID_CHROMA_AGC) + core->chroma_agc = vc; + } + v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl); + /* load and configure helper modules */ if (core->board.audio_chip == V4L2_IDENT_WM8775) { @@ -1942,8 +1814,10 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap, &wm8775_info, NULL); - if (sd != NULL) + if (sd != NULL) { + core->sd_wm8775 = sd; sd->grp_id = WM8775_GID; + } } if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { @@ -1971,16 +1845,22 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, /* Sets device info at pci_dev */ pci_set_drvdata(pci_dev, dev); + dev->width = 320; + dev->height = 240; + dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + /* initial device configuration */ mutex_lock(&core->lock); cx88_set_tvnorm(core, core->tvnorm); - init_controls(core); + v4l2_ctrl_handler_setup(&core->video_hdl); + v4l2_ctrl_handler_setup(&core->audio_hdl); cx88_video_mux(core, 0); /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); video_set_drvdata(dev->video_dev, dev); + dev->video_dev->ctrl_handler = &core->video_hdl; err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { @@ -2007,6 +1887,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, dev->radio_dev = cx88_vdev_init(core,dev->pci, &cx8800_radio_template,"radio"); video_set_drvdata(dev->radio_dev, dev); + dev->radio_dev->ctrl_handler = &core->audio_hdl; err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index c9659def2a78..0cae0fd9e164 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -26,6 +26,7 @@ #include <linux/kdev_t.h> #include <media/v4l2-device.h> +#include <media/v4l2-fh.h> #include <media/tuner.h> #include <media/tveeprom.h> #include <media/videobuf-dma-sg.h> @@ -115,15 +116,6 @@ struct cx8800_fmt { u32 cxformat; }; -struct cx88_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 sreg; - u32 mask; - u32 shift; -}; - /* ----------------------------------------------------------- */ /* SRAM memory management data (see cx88-core.c) */ @@ -359,6 +351,10 @@ struct cx88_core { /* config info -- analog */ struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler video_hdl; + struct v4l2_ctrl *chroma_agc; + struct v4l2_ctrl_handler audio_hdl; + struct v4l2_subdev *sd_wm8775; struct i2c_client *i2c_rtc; unsigned int boardnr; struct cx88_board board; @@ -409,8 +405,6 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define WM8775_GID (1 << 0) - #define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ @@ -424,6 +418,36 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) #define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) +#define WM8775_GID (1 << 0) + +#define wm8775_s_ctrl(core, id, val) \ + do { \ + struct v4l2_ctrl *ctrl_ = \ + v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \ + if (ctrl_ && !core->i2c_rc) { \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 1); \ + v4l2_ctrl_s_ctrl(ctrl_, val); \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 0); \ + } \ + } while (0) + +#define wm8775_g_ctrl(core, id) \ + ({ \ + struct v4l2_ctrl *ctrl_ = \ + v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \ + s32 val = 0; \ + if (ctrl_ && !core->i2c_rc) { \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 1); \ + val = v4l2_ctrl_g_ctrl(ctrl_); \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 0); \ + } \ + val; \ + }) + struct cx8800_dev; struct cx8802_dev; @@ -431,19 +455,11 @@ struct cx8802_dev; /* function 0: video stuff */ struct cx8800_fh { + struct v4l2_fh fh; struct cx8800_dev *dev; - enum v4l2_buf_type type; - int radio; unsigned int resources; - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - /* video capture */ - const struct cx8800_fmt *fmt; - unsigned int width,height; struct videobuf_queue vidq; /* vbi capture */ @@ -468,6 +484,8 @@ struct cx8800_dev { struct pci_dev *pci; unsigned char pci_rev,pci_lat; + const struct cx8800_fmt *fmt; + unsigned int width, height; /* capture queues */ struct cx88_dmaqueue vidq; @@ -488,6 +506,7 @@ struct cx8800_dev { /* function 2: mpeg stuff */ struct cx8802_fh { + struct v4l2_fh fh; struct cx8802_dev *dev; struct videobuf_queue mpegq; }; @@ -552,7 +571,7 @@ struct cx8802_dev { unsigned char mpeg_active; /* nonzero if mpeg encoder is active */ /* mpeg params */ - struct cx2341x_mpeg_params params; + struct cx2341x_handler cxhdl; #endif #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) @@ -722,11 +741,8 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev); /* ----------------------------------------------------------- */ /* cx88-video.c*/ -extern const u32 cx88_user_ctrls[]; -extern int cx8800_ctrl_query(struct cx88_core *core, - struct v4l2_queryctrl *qctrl); int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i); int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f); -int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl); -int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl); int cx88_video_mux(struct cx88_core *core, unsigned int input); +void cx88_querycap(struct file *file, struct cx88_core *core, + struct v4l2_capability *cap); diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig index 9337b5605c90..52c5ca68cb3d 100644 --- a/drivers/media/video/davinci/Kconfig +++ b/drivers/media/video/davinci/Kconfig @@ -1,30 +1,34 @@ -config DISPLAY_DAVINCI_DM646X_EVM - tristate "DM646x EVM Video Display" - depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM - select VIDEOBUF_DMA_CONTIG +config VIDEO_DAVINCI_VPIF_DISPLAY + tristate "DM646x/DA850/OMAPL138 EVM Video Display" + depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM) + select VIDEOBUF2_DMA_CONTIG select VIDEO_DAVINCI_VPIF - select VIDEO_ADV7343 - select VIDEO_THS7303 + select VIDEO_ADV7343 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_THS7303 if VIDEO_HELPER_CHIPS_AUTO help - Support for DM6467 based display device. + Enables Davinci VPIF module used for display devices. + This module is common for following DM6467/DA850/OMAPL138 + based display devices. To compile this driver as a module, choose M here: the module will be called vpif_display. -config CAPTURE_DAVINCI_DM646X_EVM - tristate "DM646x EVM Video Capture" - depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM - select VIDEOBUF_DMA_CONTIG +config VIDEO_DAVINCI_VPIF_CAPTURE + tristate "DM646x/DA850/OMAPL138 EVM Video Capture" + depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM) + select VIDEOBUF2_DMA_CONTIG select VIDEO_DAVINCI_VPIF help - Support for DM6467 based capture device. + Enables Davinci VPIF module used for captur devices. + This module is common for following DM6467/DA850/OMAPL138 + based capture devices. To compile this driver as a module, choose M here: the module will be called vpif_capture. config VIDEO_DAVINCI_VPIF tristate "DaVinci VPIF Driver" - depends on DISPLAY_DAVINCI_DM646X_EVM + depends on VIDEO_DAVINCI_VPIF_DISPLAY || VIDEO_DAVINCI_VPIF_CAPTURE help Support for DaVinci VPIF Driver. diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index ae7dafb689ab..74ed92d09257 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -5,10 +5,10 @@ # VPIF obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o -#DM646x EVM Display driver -obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o -#DM646x EVM Capture driver -obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o +#VPIF Display driver +obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif_display.o +#VPIF Capture driver +obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif_capture.o # Capture: DM6446 and DM355 obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c index e106b72810a9..6fe7034bea7c 100644 --- a/drivers/media/video/davinci/vpbe_display.c +++ b/drivers/media/video/davinci/vpbe_display.c @@ -1083,7 +1083,7 @@ vpbe_display_s_dv_preset(struct file *file, void *priv, } /* Set the given standard in the encoder */ - if (NULL != vpbe_dev->ops.s_dv_preset) + if (!vpbe_dev->ops.s_dv_preset) return -EINVAL; ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); @@ -1517,6 +1517,8 @@ static int vpbe_display_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct v4l2_dbg_match *match = ®->match; + struct vpbe_fh *fh = file->private_data; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; if (match->type >= 2) { v4l2_subdev_call(vpbe_dev->venc, diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c index af9680273ff9..b3637aff8fee 100644 --- a/drivers/media/video/davinci/vpif.c +++ b/drivers/media/video/davinci/vpif.c @@ -1,5 +1,5 @@ /* - * vpif - DM646x Video Port Interface driver + * vpif - Video Port Interface driver * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) * that receiveing video byte stream and two channels(2, 3) for video output. * The hardware supports SDTV, HDTV formats, raw data capture. @@ -23,6 +23,8 @@ #include <linux/spinlock.h> #include <linux/kernel.h> #include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> #include <mach/hardware.h> #include "vpif.h" @@ -40,6 +42,7 @@ static struct resource *res; spinlock_t vpif_lock; void __iomem *vpif_base; +struct clk *vpif_clk; /** * ch_params: video standard configuration parameters for vpif @@ -346,7 +349,7 @@ static void config_vpif_params(struct vpif_params *vpifparams, value = regr(reg); /* Set data width */ - value &= ((~(unsigned int)(0x3)) << + value &= ~(0x3u << VPIF_CH_DATA_WIDTH_BIT); value |= ((vpifparams->params.data_sz) << VPIF_CH_DATA_WIDTH_BIT); @@ -434,10 +437,19 @@ static int __init vpif_probe(struct platform_device *pdev) goto fail; } + vpif_clk = clk_get(&pdev->dev, "vpif"); + if (IS_ERR(vpif_clk)) { + status = PTR_ERR(vpif_clk); + goto clk_fail; + } + clk_enable(vpif_clk); + spin_lock_init(&vpif_lock); dev_info(&pdev->dev, "vpif probe success\n"); return 0; +clk_fail: + iounmap(vpif_base); fail: release_mem_region(res->start, res_len); return status; @@ -445,15 +457,44 @@ fail: static int __devexit vpif_remove(struct platform_device *pdev) { + if (vpif_clk) { + clk_disable(vpif_clk); + clk_put(vpif_clk); + } + iounmap(vpif_base); release_mem_region(res->start, res_len); return 0; } +#ifdef CONFIG_PM +static int vpif_suspend(struct device *dev) +{ + clk_disable(vpif_clk); + return 0; +} + +static int vpif_resume(struct device *dev) +{ + clk_enable(vpif_clk); + return 0; +} + +static const struct dev_pm_ops vpif_pm = { + .suspend = vpif_suspend, + .resume = vpif_resume, +}; + +#define vpif_pm_ops (&vpif_pm) +#else +#define vpif_pm_ops NULL +#endif + static struct platform_driver vpif_driver = { .driver = { .name = "vpif", .owner = THIS_MODULE, + .pm = vpif_pm_ops, }, .remove = __devexit_p(vpif_remove), .probe = vpif_probe, diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h index 8bcac65f9294..c2ce4d97c279 100644 --- a/drivers/media/video/davinci/vpif.h +++ b/drivers/media/video/davinci/vpif.h @@ -211,6 +211,12 @@ static inline void vpif_clr_bit(u32 reg, u32 bit) #define VPIF_CH3_INT_CTRL_SHIFT (6) #define VPIF_CH_INT_CTRL_SHIFT (6) +#define VPIF_CH2_CLIP_ANC_EN 14 +#define VPIF_CH2_CLIP_ACTIVE_EN 13 + +#define VPIF_CH3_CLIP_ANC_EN 14 +#define VPIF_CH3_CLIP_ACTIVE_EN 13 + /* enabled interrupt on both the fields on vpid_ch0_ctrl register */ #define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\ (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL)) @@ -515,6 +521,30 @@ static inline void channel3_raw_enable(int enable, u8 index) vpif_clr_bit(VPIF_CH3_CTRL, mask); } +/* function to enable clipping (for both active and blanking regions) on ch 2 */ +static inline void channel2_clipping_enable(int enable) +{ + if (enable) { + vpif_set_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ANC_EN); + vpif_set_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ACTIVE_EN); + } else { + vpif_clr_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ANC_EN); + vpif_clr_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ACTIVE_EN); + } +} + +/* function to enable clipping (for both active and blanking regions) on ch 2 */ +static inline void channel3_clipping_enable(int enable) +{ + if (enable) { + vpif_set_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ANC_EN); + vpif_set_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ACTIVE_EN); + } else { + vpif_clr_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ANC_EN); + vpif_clr_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ACTIVE_EN); + } +} + /* inline function to set buffer addresses in case of Y/C non mux mode */ static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, unsigned long btm_strt_luma, @@ -569,6 +599,21 @@ static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); } +static inline int vpif_intr_status(int channel) +{ + int status = 0; + int mask; + + if (channel < 0 || channel > 3) + return 0; + + mask = 1 << channel; + status = regr(VPIF_STATUS) & mask; + regw(status, VPIF_STATUS_CLR); + + return status; +} + #define VPIF_MAX_NAME (30) /* This structure will store size parameters as per the mode selected by user */ diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 96046957bf21..266025e5d81d 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -80,108 +80,45 @@ static struct vpif_config_params config_params = { /* global variables */ static struct vpif_device vpif_obj = { {NULL} }; static struct device *vpif_dev; - -/** - * vpif_uservirt_to_phys : translate user/virtual address to phy address - * @virtp: user/virtual address - * - * This inline function is used to convert user space virtual address to - * physical address. - */ -static inline u32 vpif_uservirt_to_phys(u32 virtp) -{ - unsigned long physp = 0; - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - - vma = find_vma(mm, virtp); - - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) - physp = virt_to_phys((void *)virtp); - else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) - /** - * this will catch, kernel-allocated, mmaped-to-usermode - * addresses - */ - physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); - else { - /* otherwise, use get_user_pages() for general userland pages */ - int res, nr_pages = 1; - struct page *pages; - - down_read(¤t->mm->mmap_sem); - - res = get_user_pages(current, current->mm, - virtp, nr_pages, 1, 0, &pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (res == nr_pages) - physp = __pa(page_address(&pages[0]) + - (virtp & ~PAGE_MASK)); - else { - vpif_err("get_user_pages failed\n"); - return 0; - } - } - return physp; -} +static void vpif_calculate_offsets(struct channel_obj *ch); +static void vpif_config_addr(struct channel_obj *ch, int muxmode); /** * buffer_prepare : callback function for buffer prepare - * @q : buffer queue ptr - * @vb: ptr to video buffer - * @field: field info + * @vb: ptr to vb2_buffer * - * This is the callback function for buffer prepare when videobuf_qbuf() + * This is the callback function for buffer prepare when vb2_qbuf() * function is called. The buffer is prepared and user space virtual address * or user address is converted into physical address */ -static int vpif_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int vpif_buffer_prepare(struct vb2_buffer *vb) { /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_queue *q = vb->vb2_queue; struct channel_obj *ch = fh->channel; struct common_obj *common; unsigned long addr; - vpif_dbg(2, debug, "vpif_buffer_prepare\n"); common = &ch->common[VPIF_VIDEO_INDEX]; - /* If buffer is not initialized, initialize it */ - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = common->width; - vb->height = common->height; - vb->size = vb->width * vb->height; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - /** - * if user pointer memory mechanism is used, get the physical - * address of the buffer - */ - if (V4L2_MEMORY_USERPTR == common->memory) { - if (0 == vb->baddr) { - vpif_dbg(1, debug, "buffer address is 0\n"); - return -EINVAL; - - } - vb->boff = vpif_uservirt_to_phys(vb->baddr); - if (!IS_ALIGNED(vb->boff, 8)) + if (vb->state != VB2_BUF_STATE_ACTIVE && + vb->state != VB2_BUF_STATE_PREPARED) { + vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage); + if (vb2_plane_vaddr(vb, 0) && + vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) goto exit; - } + addr = vb2_dma_contig_plane_dma_addr(vb, 0); - addr = vb->boff; - if (q->streaming) { - if (!IS_ALIGNED((addr + common->ytop_off), 8) || - !IS_ALIGNED((addr + common->ybtm_off), 8) || - !IS_ALIGNED((addr + common->ctop_off), 8) || - !IS_ALIGNED((addr + common->cbtm_off), 8)) - goto exit; + if (q->streaming) { + if (!IS_ALIGNED((addr + common->ytop_off), 8) || + !IS_ALIGNED((addr + common->ybtm_off), 8) || + !IS_ALIGNED((addr + common->ctop_off), 8) || + !IS_ALIGNED((addr + common->cbtm_off), 8)) + goto exit; + } } return 0; exit: @@ -190,49 +127,79 @@ exit: } /** - * vpif_buffer_setup : Callback function for buffer setup. - * @q: buffer queue ptr - * @count: number of buffers - * @size: size of the buffer + * vpif_buffer_queue_setup : Callback function for buffer setup. + * @vq: vb2_queue ptr + * @fmt: v4l2 format + * @nbuffers: ptr to number of buffers requested by application + * @nplanes:: contains number of distinct video planes needed to hold a frame + * @sizes[]: contains the size (in bytes) of each plane. + * @alloc_ctxs: ptr to allocation context * * This callback function is called when reqbuf() is called to adjust * the buffer count and buffer size */ -static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) +static int vpif_buffer_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vq); struct channel_obj *ch = fh->channel; struct common_obj *common; + unsigned long size; common = &ch->common[VPIF_VIDEO_INDEX]; vpif_dbg(2, debug, "vpif_buffer_setup\n"); /* If memory type is not mmap, return */ - if (V4L2_MEMORY_MMAP != common->memory) - return 0; + if (V4L2_MEMORY_MMAP == common->memory) { + /* Calculate the size of the buffer */ + size = config_params.channel_bufsize[ch->channel_id]; + /* + * Checking if the buffer size exceeds the available buffer + * ycmux_mode = 0 means 1 channel mode HD and + * ycmux_mode = 1 means 2 channels mode SD + */ + if (ch->vpifparams.std_info.ycmux_mode == 0) { + if (config_params.video_limit[ch->channel_id]) + while (size * *nbuffers > + (config_params.video_limit[0] + + config_params.video_limit[1])) + (*nbuffers)--; + } else { + if (config_params.video_limit[ch->channel_id]) + while (size * *nbuffers > + config_params.video_limit[ch->channel_id]) + (*nbuffers)--; + } + + } else { + size = common->fmt.fmt.pix.sizeimage; + } + + if (*nbuffers < config_params.min_numbuffers) + *nbuffers = config_params.min_numbuffers; - /* Calculate the size of the buffer */ - *size = config_params.channel_bufsize[ch->channel_id]; + *nplanes = 1; + sizes[0] = size; + alloc_ctxs[0] = common->alloc_ctx; - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; return 0; } /** * vpif_buffer_queue : Callback function to add buffer to DMA queue - * @q: ptr to videobuf_queue - * @vb: ptr to videobuf_buffer + * @vb: ptr to vb2_buffer */ -static void vpif_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void vpif_buffer_queue(struct vb2_buffer *vb) { /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue); struct channel_obj *ch = fh->channel; + struct vpif_cap_buffer *buf = container_of(vb, + struct vpif_cap_buffer, vb); struct common_obj *common; common = &ch->common[VPIF_VIDEO_INDEX]; @@ -240,43 +207,189 @@ static void vpif_buffer_queue(struct videobuf_queue *q, vpif_dbg(2, debug, "vpif_buffer_queue\n"); /* add the buffer to the DMA queue */ - list_add_tail(&vb->queue, &common->dma_queue); - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; + list_add_tail(&buf->list, &common->dma_queue); } /** - * vpif_buffer_release : Callback function to free buffer - * @q: buffer queue ptr - * @vb: ptr to video buffer + * vpif_buf_cleanup : Callback function to free buffer + * @vb: ptr to vb2_buffer * - * This function is called from the videobuf layer to free memory + * This function is called from the videobuf2 layer to free memory * allocated to the buffers */ -static void vpif_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void vpif_buf_cleanup(struct vb2_buffer *vb) { /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue); + struct vpif_cap_buffer *buf = container_of(vb, + struct vpif_cap_buffer, vb); struct channel_obj *ch = fh->channel; struct common_obj *common; + unsigned long flags; common = &ch->common[VPIF_VIDEO_INDEX]; - videobuf_dma_contig_free(q, vb); - vb->state = VIDEOBUF_NEEDS_INIT; + spin_lock_irqsave(&common->irqlock, flags); + if (vb->state == VB2_BUF_STATE_ACTIVE) + list_del_init(&buf->list); + spin_unlock_irqrestore(&common->irqlock, flags); + } -static struct videobuf_queue_ops video_qops = { - .buf_setup = vpif_buffer_setup, - .buf_prepare = vpif_buffer_prepare, - .buf_queue = vpif_buffer_queue, - .buf_release = vpif_buffer_release, -}; +static void vpif_wait_prepare(struct vb2_queue *vq) +{ + struct vpif_fh *fh = vb2_get_drv_priv(vq); + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_unlock(&common->lock); +} + +static void vpif_wait_finish(struct vb2_queue *vq) +{ + struct vpif_fh *fh = vb2_get_drv_priv(vq); + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); +} + +static int vpif_buffer_init(struct vb2_buffer *vb) +{ + struct vpif_cap_buffer *buf = container_of(vb, + struct vpif_cap_buffer, vb); + + INIT_LIST_HEAD(&buf->list); + + return 0; +} static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = { {1, 1} }; +static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vpif_capture_config *vpif_config_data = + vpif_dev->platform_data; + struct vpif_fh *fh = vb2_get_drv_priv(vq); + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct vpif_params *vpif = &ch->vpifparams; + unsigned long addr = 0; + int ret; + + /* If buffer queue is empty, return error */ + if (list_empty(&common->dma_queue)) { + vpif_dbg(1, debug, "buffer queue is empty\n"); + return -EIO; + } + + /* Get the next frame from the buffer queue */ + common->cur_frm = common->next_frm = list_entry(common->dma_queue.next, + struct vpif_cap_buffer, list); + /* Remove buffer from the buffer queue */ + list_del(&common->cur_frm->list); + /* Mark state of the current frame to active */ + common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; + /* Initialize field_id and started member */ + ch->field_id = 0; + common->started = 1; + addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0); + + /* Calculate the offset for Y and C data in the buffer */ + vpif_calculate_offsets(ch); + + if ((vpif->std_info.frm_fmt && + ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && + (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || + (!vpif->std_info.frm_fmt && + (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { + vpif_dbg(1, debug, "conflict in field format and std format\n"); + return -EINVAL; + } + + /* configure 1 or 2 channel mode */ + ret = vpif_config_data->setup_input_channel_mode + (vpif->std_info.ycmux_mode); + + if (ret < 0) { + vpif_dbg(1, debug, "can't set vpif channel mode\n"); + return ret; + } + + /* Call vpif_set_params function to set the parameters and addresses */ + ret = vpif_set_video_params(vpif, ch->channel_id); + + if (ret < 0) { + vpif_dbg(1, debug, "can't set video params\n"); + return ret; + } + + common->started = ret; + vpif_config_addr(ch, ret); + + common->set_addr(addr + common->ytop_off, + addr + common->ybtm_off, + addr + common->ctop_off, + addr + common->cbtm_off); + + /** + * Set interrupt for both the fields in VPIF Register enable channel in + * VPIF register + */ + if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { + channel0_intr_assert(); + channel0_intr_enable(1); + enable_channel0(1); + } + if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || + (common->started == 2)) { + channel1_intr_assert(); + channel1_intr_enable(1); + enable_channel1(1); + } + channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; + + return 0; +} + +/* abort streaming and wait for last buffer */ +static int vpif_stop_streaming(struct vb2_queue *vq) +{ + struct vpif_fh *fh = vb2_get_drv_priv(vq); + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + if (!vb2_is_streaming(vq)) + return 0; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + /* release all active buffers */ + while (!list_empty(&common->dma_queue)) { + common->next_frm = list_entry(common->dma_queue.next, + struct vpif_cap_buffer, list); + list_del(&common->next_frm->list); + vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR); + } + + return 0; +} + +static struct vb2_ops video_qops = { + .queue_setup = vpif_buffer_queue_setup, + .wait_prepare = vpif_wait_prepare, + .wait_finish = vpif_wait_finish, + .buf_init = vpif_buffer_init, + .buf_prepare = vpif_buffer_prepare, + .start_streaming = vpif_start_streaming, + .stop_streaming = vpif_stop_streaming, + .buf_cleanup = vpif_buf_cleanup, + .buf_queue = vpif_buffer_queue, +}; + /** * vpif_process_buffer_complete: process a completed buffer * @common: ptr to common channel object @@ -287,9 +400,9 @@ static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = */ static void vpif_process_buffer_complete(struct common_obj *common) { - do_gettimeofday(&common->cur_frm->ts); - common->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&common->cur_frm->done); + do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp); + vb2_buffer_done(&common->cur_frm->vb, + VB2_BUF_STATE_DONE); /* Make curFrm pointing to nextFrm */ common->cur_frm = common->next_frm; } @@ -307,14 +420,11 @@ static void vpif_schedule_next_buffer(struct common_obj *common) unsigned long addr = 0; common->next_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); + struct vpif_cap_buffer, list); /* Remove that buffer from the buffer queue */ - list_del(&common->next_frm->queue); - common->next_frm->state = VIDEOBUF_ACTIVE; - if (V4L2_MEMORY_USERPTR == common->memory) - addr = common->next_frm->boff; - else - addr = videobuf_to_dma_contig(common->next_frm); + list_del(&common->next_frm->list); + common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; + addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0); /* Set top and bottom field addresses in VPIF registers */ common->set_addr(addr + common->ytop_off, @@ -341,6 +451,9 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) int fid = -1, i; channel_id = *(int *)(dev_id); + if (!vpif_intr_status(channel_id)) + return IRQ_NONE; + ch = dev->dev[channel_id]; field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; @@ -485,10 +598,7 @@ static void vpif_calculate_offsets(struct channel_obj *ch) } else vid_ch->buf_field = common->fmt.fmt.pix.field; - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = common->fmt.fmt.pix.sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; + sizeimage = common->fmt.fmt.pix.sizeimage; hpitch = common->fmt.fmt.pix.bytesperline; vpitch = sizeimage / (hpitch * 2); @@ -640,10 +750,7 @@ static int vpif_check_format(struct channel_obj *ch, hpitch = vpif_params->std_info.width; } - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = pixfmt->sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; + sizeimage = pixfmt->sizeimage; vpitch = sizeimage / (hpitch * 2); @@ -703,7 +810,7 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode) } /** - * vpfe_mmap : It is used to map kernel space buffers into user spaces + * vpif_mmap : It is used to map kernel space buffers into user spaces * @filep: file pointer * @vma: ptr to vm_area_struct */ @@ -716,7 +823,7 @@ static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) vpif_dbg(2, debug, "vpif_mmap\n"); - return videobuf_mmap_mapper(&common->buffer_queue, vma); + return vb2_mmap(&common->buffer_queue, vma); } /** @@ -733,7 +840,7 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait) vpif_dbg(2, debug, "vpif_poll\n"); if (common->started) - return videobuf_poll_stream(filep, &common->buffer_queue, wait); + return vb2_poll(&common->buffer_queue, filep, wait); return 0; } @@ -812,7 +919,7 @@ static int vpif_open(struct file *filep) * vpif_release : function to clean up file close * @filep: file pointer * - * This function deletes buffer queue, frees the buffers and the vpfe file + * This function deletes buffer queue, frees the buffers and the vpif file * handle */ static int vpif_release(struct file *filep) @@ -841,8 +948,8 @@ static int vpif_release(struct file *filep) } common->started = 0; /* Free buffers allocated */ - videobuf_queue_cancel(&common->buffer_queue); - videobuf_mmap_free(&common->buffer_queue); + vb2_queue_release(&common->buffer_queue); + vb2_dma_contig_cleanup_ctx(common->alloc_ctx); } /* Decrement channel usrs counter */ @@ -872,6 +979,7 @@ static int vpif_reqbufs(struct file *file, void *priv, struct channel_obj *ch = fh->channel; struct common_obj *common; u8 index = 0; + struct vb2_queue *q; vpif_dbg(2, debug, "vpif_reqbufs\n"); @@ -887,7 +995,7 @@ static int vpif_reqbufs(struct file *file, void *priv, } } - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type) + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type || !vpif_dev) return -EINVAL; index = VPIF_VIDEO_INDEX; @@ -897,14 +1005,21 @@ static int vpif_reqbufs(struct file *file, void *priv, if (0 != common->io_usrs) return -EBUSY; - /* Initialize videobuf queue as per the buffer type */ - videobuf_queue_dma_contig_init(&common->buffer_queue, - &video_qops, NULL, - &common->irqlock, - reqbuf->type, - common->fmt.fmt.pix.field, - sizeof(struct videobuf_buffer), fh, - &common->lock); + /* Initialize videobuf2 queue as per the buffer type */ + common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev); + if (!common->alloc_ctx) { + vpif_err("Failed to get the context\n"); + return -EINVAL; + } + q = &common->buffer_queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = fh; + q->ops = &video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct vpif_cap_buffer); + + vb2_queue_init(q); /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; @@ -915,7 +1030,7 @@ static int vpif_reqbufs(struct file *file, void *priv, INIT_LIST_HEAD(&common->dma_queue); /* Allocate buffers */ - return videobuf_reqbufs(&common->buffer_queue, reqbuf); + return vb2_reqbufs(&common->buffer_queue, reqbuf); } /** @@ -941,7 +1056,7 @@ static int vpif_querybuf(struct file *file, void *priv, return -EINVAL; } - return videobuf_querybuf(&common->buffer_queue, buf); + return vb2_querybuf(&common->buffer_queue, buf); } /** @@ -957,10 +1072,6 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct v4l2_buffer tbuf = *buf; - struct videobuf_buffer *buf1; - unsigned long addr = 0; - unsigned long flags; - int ret = 0; vpif_dbg(2, debug, "vpif_qbuf\n"); @@ -970,76 +1081,11 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) } if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh io not allowed \n"); + vpif_err("fh io not allowed\n"); return -EACCES; } - if (!(list_empty(&common->dma_queue)) || - (common->cur_frm != common->next_frm) || - !common->started || - (common->started && (0 == ch->field_id))) - return videobuf_qbuf(&common->buffer_queue, buf); - - /* bufferqueue is empty store buffer address in VPIF registers */ - mutex_lock(&common->buffer_queue.vb_lock); - buf1 = common->buffer_queue.bufs[tbuf.index]; - - if ((buf1->state == VIDEOBUF_QUEUED) || - (buf1->state == VIDEOBUF_ACTIVE)) { - vpif_err("invalid state\n"); - goto qbuf_exit; - } - - switch (buf1->memory) { - case V4L2_MEMORY_MMAP: - if (buf1->baddr == 0) - goto qbuf_exit; - break; - - case V4L2_MEMORY_USERPTR: - if (tbuf.length < buf1->bsize) - goto qbuf_exit; - - if ((VIDEOBUF_NEEDS_INIT != buf1->state) - && (buf1->baddr != tbuf.m.userptr)) { - vpif_buffer_release(&common->buffer_queue, buf1); - buf1->baddr = tbuf.m.userptr; - } - break; - - default: - goto qbuf_exit; - } - - local_irq_save(flags); - ret = vpif_buffer_prepare(&common->buffer_queue, buf1, - common->buffer_queue.field); - if (ret < 0) { - local_irq_restore(flags); - goto qbuf_exit; - } - - buf1->state = VIDEOBUF_ACTIVE; - - if (V4L2_MEMORY_USERPTR == common->memory) - addr = buf1->boff; - else - addr = videobuf_to_dma_contig(buf1); - - common->next_frm = buf1; - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); - - local_irq_restore(flags); - list_add_tail(&buf1->stream, &common->buffer_queue.stream); - mutex_unlock(&common->buffer_queue.vb_lock); - return 0; - -qbuf_exit: - mutex_unlock(&common->buffer_queue.vb_lock); - return -EINVAL; + return vb2_qbuf(&common->buffer_queue, buf); } /** @@ -1056,8 +1102,8 @@ static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) vpif_dbg(2, debug, "vpif_dqbuf\n"); - return videobuf_dqbuf(&common->buffer_queue, buf, - file->f_flags & O_NONBLOCK); + return vb2_dqbuf(&common->buffer_queue, buf, + (file->f_flags & O_NONBLOCK)); } /** @@ -1070,13 +1116,11 @@ static int vpif_streamon(struct file *file, void *priv, enum v4l2_buf_type buftype) { - struct vpif_capture_config *config = vpif_dev->platform_data; struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; struct vpif_params *vpif; - unsigned long addr = 0; int ret = 0; vpif_dbg(2, debug, "vpif_streamon\n"); @@ -1122,95 +1166,13 @@ static int vpif_streamon(struct file *file, void *priv, return ret; } - /* Call videobuf_streamon to start streaming in videobuf */ - ret = videobuf_streamon(&common->buffer_queue); + /* Call vb2_streamon to start streaming in videobuf2 */ + ret = vb2_streamon(&common->buffer_queue, buftype); if (ret) { - vpif_dbg(1, debug, "videobuf_streamon\n"); + vpif_dbg(1, debug, "vb2_streamon\n"); return ret; } - /* If buffer queue is empty, return error */ - if (list_empty(&common->dma_queue)) { - vpif_dbg(1, debug, "buffer queue is empty\n"); - ret = -EIO; - goto exit; - } - - /* Get the next frame from the buffer queue */ - common->cur_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - common->next_frm = common->cur_frm; - - /* Remove buffer from the buffer queue */ - list_del(&common->cur_frm->queue); - /* Mark state of the current frame to active */ - common->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - ch->field_id = 0; - common->started = 1; - - if (V4L2_MEMORY_USERPTR == common->memory) - addr = common->cur_frm->boff; - else - addr = videobuf_to_dma_contig(common->cur_frm); - - /* Calculate the offset for Y and C data in the buffer */ - vpif_calculate_offsets(ch); - - if ((vpif->std_info.frm_fmt && - ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && - (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || - (!vpif->std_info.frm_fmt && - (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { - vpif_dbg(1, debug, "conflict in field format and std format\n"); - ret = -EINVAL; - goto exit; - } - - /* configure 1 or 2 channel mode */ - ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set vpif channel mode\n"); - goto exit; - } - - /* Call vpif_set_params function to set the parameters and addresses */ - ret = vpif_set_video_params(vpif, ch->channel_id); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set video params\n"); - goto exit; - } - - common->started = ret; - vpif_config_addr(ch, ret); - - common->set_addr(addr + common->ytop_off, - addr + common->ybtm_off, - addr + common->ctop_off, - addr + common->cbtm_off); - - /** - * Set interrupt for both the fields in VPIF Register enable channel in - * VPIF register - */ - if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { - channel0_intr_assert(); - channel0_intr_enable(1); - enable_channel0(1); - } - if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || - (common->started == 2)) { - channel1_intr_assert(); - channel1_intr_enable(1); - enable_channel1(1); - } - channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; - return ret; - -exit: - videobuf_streamoff(&common->buffer_queue); return ret; } @@ -1265,7 +1227,7 @@ static int vpif_streamoff(struct file *file, void *priv, if (ret && (ret != -ENOIOCTLCMD)) vpif_dbg(1, debug, "stream off failed in subdev\n"); - return videobuf_streamoff(&common->buffer_queue); + return vb2_streamoff(&common->buffer_queue, buftype); } /** @@ -1679,7 +1641,7 @@ static int vpif_querycap(struct file *file, void *priv, cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); - strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); + strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info)); strlcpy(cap->card, config->card_name, sizeof(cap->card)); return 0; @@ -2168,6 +2130,7 @@ static __init int vpif_probe(struct platform_device *pdev) struct video_device *vfd; struct resource *res; int subdev_count; + size_t size; vpif_dev = &pdev->dev; @@ -2186,8 +2149,8 @@ static __init int vpif_probe(struct platform_device *pdev) k = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { - if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, - "DM646x_Capture", + if (request_irq(i, vpif_channel_isr, IRQF_SHARED, + "VPIF_Capture", (void *)(&vpif_obj.dev[k]->channel_id))) { err = -EBUSY; i--; @@ -2216,12 +2179,29 @@ static __init int vpif_probe(struct platform_device *pdev) vfd->v4l2_dev = &vpif_obj.v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFCapture_DRIVER_V%s", + "VPIF_Capture_DRIVER_V%s", VPIF_CAPTURE_VERSION); /* Set video_dev to the video device */ ch->video_dev = vfd; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + size = resource_size(res); + /* The resources are divided into two equal memory and when we + * have HD output we can add them together + */ + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + /* only enabled if second resource exists */ + config_params.video_limit[ch->channel_id] = 0; + if (size) + config_params.video_limit[ch->channel_id] = + size/2; + } + } + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { ch = vpif_obj.dev[j]; ch->channel_id = j; @@ -2275,8 +2255,7 @@ static __init int vpif_probe(struct platform_device *pdev) vpif_obj.sd[i]->grp_id = 1 << i; } - v4l2_info(&vpif_obj.v4l2_dev, - "DM646x VPIF capture driver initialized\n"); + v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n"); return 0; probe_subdev_out: @@ -2333,26 +2312,70 @@ static int vpif_remove(struct platform_device *device) return 0; } +#ifdef CONFIG_PM /** * vpif_suspend: vpif device suspend - * - * TODO: Add suspend code here */ -static int -vpif_suspend(struct device *dev) +static int vpif_suspend(struct device *dev) { - return -1; + + struct common_obj *common; + struct channel_obj *ch; + int i; + + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); + if (ch->usrs && common->io_usrs) { + /* Disable channel */ + if (ch->channel_id == VPIF_CHANNEL0_VIDEO) { + enable_channel0(0); + channel0_intr_enable(0); + } + if (ch->channel_id == VPIF_CHANNEL1_VIDEO || + common->started == 2) { + enable_channel1(0); + channel1_intr_enable(0); + } + } + mutex_unlock(&common->lock); + } + + return 0; } -/** +/* * vpif_resume: vpif device suspend - * - * TODO: Add resume code here */ -static int -vpif_resume(struct device *dev) +static int vpif_resume(struct device *dev) { - return -1; + struct common_obj *common; + struct channel_obj *ch; + int i; + + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); + if (ch->usrs && common->io_usrs) { + /* Disable channel */ + if (ch->channel_id == VPIF_CHANNEL0_VIDEO) { + enable_channel0(1); + channel0_intr_enable(1); + } + if (ch->channel_id == VPIF_CHANNEL1_VIDEO || + common->started == 2) { + enable_channel1(1); + channel1_intr_enable(1); + } + } + mutex_unlock(&common->lock); + } + + return 0; } static const struct dev_pm_ops vpif_dev_pm_ops = { @@ -2360,11 +2383,16 @@ static const struct dev_pm_ops vpif_dev_pm_ops = { .resume = vpif_resume, }; +#define vpif_pm_ops (&vpif_dev_pm_ops) +#else +#define vpif_pm_ops NULL +#endif + static __refdata struct platform_driver vpif_driver = { .driver = { .name = "vpif_capture", .owner = THIS_MODULE, - .pm = &vpif_dev_pm_ops, + .pm = vpif_pm_ops, }, .probe = vpif_probe, .remove = vpif_remove, diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h index a693d4ebda55..3511510f43ee 100644 --- a/drivers/media/video/davinci/vpif_capture.h +++ b/drivers/media/video/davinci/vpif_capture.h @@ -26,7 +26,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-device.h> #include <media/videobuf-core.h> -#include <media/videobuf-dma-contig.h> +#include <media/videobuf2-dma-contig.h> #include <media/davinci/vpif_types.h> #include "vpif.h" @@ -60,11 +60,16 @@ struct video_obj { u32 input_idx; }; +struct vpif_cap_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + struct common_obj { /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *cur_frm; + struct vpif_cap_buffer *cur_frm; /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *next_frm; + struct vpif_cap_buffer *next_frm; /* * This field keeps track of type of buffer exchange mechanism * user has selected @@ -73,7 +78,9 @@ struct common_obj { /* Used to store pixel format */ struct v4l2_format fmt; /* Buffer queue used in video-buf */ - struct videobuf_queue buffer_queue; + struct vb2_queue buffer_queue; + /* allocator-specific contexts for each plane */ + struct vb2_alloc_ctx *alloc_ctx; /* Queue of filled frames */ struct list_head dma_queue; /* Used in video-buf */ @@ -151,6 +158,7 @@ struct vpif_config_params { u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; u8 default_device[VPIF_CAPTURE_NUM_CHANNELS]; + u32 video_limit[VPIF_CAPTURE_NUM_CHANNELS]; u8 max_device_type; }; /* Struct which keeps track of the line numbers for the sliced vbi service */ diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index e6488ee7db18..e129c98921ad 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -46,7 +46,7 @@ MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(VPIF_DISPLAY_VERSION); -#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) +#define VPIF_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) #define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) #define vpif_dbg(level, debug, fmt, arg...) \ @@ -82,89 +82,38 @@ static struct vpif_config_params config_params = { static struct vpif_device vpif_obj = { {NULL} }; static struct device *vpif_dev; +static void vpif_calculate_offsets(struct channel_obj *ch); +static void vpif_config_addr(struct channel_obj *ch, int muxmode); /* - * vpif_uservirt_to_phys: This function is used to convert user - * space virtual address to physical address. - */ -static u32 vpif_uservirt_to_phys(u32 virtp) -{ - struct mm_struct *mm = current->mm; - unsigned long physp = 0; - struct vm_area_struct *vma; - - vma = find_vma(mm, virtp); - - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) { - physp = virt_to_phys((void *)virtp); - } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { - /* this will catch, kernel-allocated, mmaped-to-usermode addr */ - physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); - } else { - /* otherwise, use get_user_pages() for general userland pages */ - int res, nr_pages = 1; - struct page *pages; - down_read(¤t->mm->mmap_sem); - - res = get_user_pages(current, current->mm, - virtp, nr_pages, 1, 0, &pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (res == nr_pages) { - physp = __pa(page_address(&pages[0]) + - (virtp & ~PAGE_MASK)); - } else { - vpif_err("get_user_pages failed\n"); - return 0; - } - } - - return physp; -} - -/* - * buffer_prepare: This is the callback function called from videobuf_qbuf() + * buffer_prepare: This is the callback function called from vb2_qbuf() * function the buffer is prepared and user space virtual address is converted * into physical address */ -static int vpif_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int vpif_buffer_prepare(struct vb2_buffer *vb) { - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_queue *q = vb->vb2_queue; struct common_obj *common; unsigned long addr; common = &fh->channel->common[VPIF_VIDEO_INDEX]; - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = common->width; - vb->height = common->height; - vb->size = vb->width * vb->height; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - - /* if user pointer memory mechanism is used, get the physical - * address of the buffer */ - if (V4L2_MEMORY_USERPTR == common->memory) { - if (!vb->baddr) { - vpif_err("buffer_address is 0\n"); - return -EINVAL; - } - - vb->boff = vpif_uservirt_to_phys(vb->baddr); - if (!ISALIGNED(vb->boff)) + if (vb->state != VB2_BUF_STATE_ACTIVE && + vb->state != VB2_BUF_STATE_PREPARED) { + vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage); + if (vb2_plane_vaddr(vb, 0) && + vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) goto buf_align_exit; - } - addr = vb->boff; - if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) { - if (!ISALIGNED(addr + common->ytop_off) || - !ISALIGNED(addr + common->ybtm_off) || - !ISALIGNED(addr + common->ctop_off) || - !ISALIGNED(addr + common->cbtm_off)) - goto buf_align_exit; + addr = vb2_dma_contig_plane_dma_addr(vb, 0); + if (q->streaming && + (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) { + if (!ISALIGNED(addr + common->ytop_off) || + !ISALIGNED(addr + common->ybtm_off) || + !ISALIGNED(addr + common->ctop_off) || + !ISALIGNED(addr + common->cbtm_off)) + goto buf_align_exit; + } } return 0; @@ -174,86 +123,255 @@ buf_align_exit: } /* - * vpif_buffer_setup: This function allocates memory for the buffers + * vpif_buffer_queue_setup: This function allocates memory for the buffers */ -static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) +static int vpif_buffer_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vq); struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + unsigned long size; + + if (V4L2_MEMORY_MMAP == common->memory) { + size = config_params.channel_bufsize[ch->channel_id]; + /* + * Checking if the buffer size exceeds the available buffer + * ycmux_mode = 0 means 1 channel mode HD and + * ycmux_mode = 1 means 2 channels mode SD + */ + if (ch->vpifparams.std_info.ycmux_mode == 0) { + if (config_params.video_limit[ch->channel_id]) + while (size * *nbuffers > + (config_params.video_limit[0] + + config_params.video_limit[1])) + (*nbuffers)--; + } else { + if (config_params.video_limit[ch->channel_id]) + while (size * *nbuffers > + config_params.video_limit[ch->channel_id]) + (*nbuffers)--; + } + } else { + size = common->fmt.fmt.pix.sizeimage; + } - if (V4L2_MEMORY_MMAP != common->memory) - return 0; - - *size = config_params.channel_bufsize[ch->channel_id]; - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; + if (*nbuffers < config_params.min_numbuffers) + *nbuffers = config_params.min_numbuffers; + *nplanes = 1; + sizes[0] = size; + alloc_ctxs[0] = common->alloc_ctx; return 0; } /* * vpif_buffer_queue: This function adds the buffer to DMA queue */ -static void vpif_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void vpif_buffer_queue(struct vb2_buffer *vb) { - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue); + struct vpif_disp_buffer *buf = container_of(vb, + struct vpif_disp_buffer, vb); + struct channel_obj *ch = fh->channel; struct common_obj *common; - common = &fh->channel->common[VPIF_VIDEO_INDEX]; + common = &ch->common[VPIF_VIDEO_INDEX]; /* add the buffer to the DMA queue */ - list_add_tail(&vb->queue, &common->dma_queue); - vb->state = VIDEOBUF_QUEUED; + list_add_tail(&buf->list, &common->dma_queue); } /* - * vpif_buffer_release: This function is called from the videobuf layer to + * vpif_buf_cleanup: This function is called from the videobuf2 layer to * free memory allocated to the buffers */ -static void vpif_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void vpif_buf_cleanup(struct vb2_buffer *vb) +{ + struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue); + struct vpif_disp_buffer *buf = container_of(vb, + struct vpif_disp_buffer, vb); + struct channel_obj *ch = fh->channel; + struct common_obj *common; + unsigned long flags; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + spin_lock_irqsave(&common->irqlock, flags); + if (vb->state == VB2_BUF_STATE_ACTIVE) + list_del_init(&buf->list); + spin_unlock_irqrestore(&common->irqlock, flags); +} + +static void vpif_wait_prepare(struct vb2_queue *vq) { - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vq); struct channel_obj *ch = fh->channel; struct common_obj *common; - unsigned int buf_size = 0; common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_unlock(&common->lock); +} - videobuf_dma_contig_free(q, vb); - vb->state = VIDEOBUF_NEEDS_INIT; +static void vpif_wait_finish(struct vb2_queue *vq) +{ + struct vpif_fh *fh = vb2_get_drv_priv(vq); + struct channel_obj *ch = fh->channel; + struct common_obj *common; - if (V4L2_MEMORY_MMAP != common->memory) - return; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); +} - buf_size = config_params.channel_bufsize[ch->channel_id]; +static int vpif_buffer_init(struct vb2_buffer *vb) +{ + struct vpif_disp_buffer *buf = container_of(vb, + struct vpif_disp_buffer, vb); + + INIT_LIST_HEAD(&buf->list); + + return 0; } -static struct videobuf_queue_ops video_qops = { - .buf_setup = vpif_buffer_setup, - .buf_prepare = vpif_buffer_prepare, - .buf_queue = vpif_buffer_queue, - .buf_release = vpif_buffer_release, -}; static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} }; +static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vpif_display_config *vpif_config_data = + vpif_dev->platform_data; + struct vpif_fh *fh = vb2_get_drv_priv(vq); + struct channel_obj *ch = fh->channel; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct vpif_params *vpif = &ch->vpifparams; + unsigned long addr = 0; + int ret; + + /* If buffer queue is empty, return error */ + if (list_empty(&common->dma_queue)) { + vpif_err("buffer queue is empty\n"); + return -EIO; + } + + /* Get the next frame from the buffer queue */ + common->next_frm = common->cur_frm = + list_entry(common->dma_queue.next, + struct vpif_disp_buffer, list); + + list_del(&common->cur_frm->list); + /* Mark state of the current frame to active */ + common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; + + /* Initialize field_id and started member */ + ch->field_id = 0; + common->started = 1; + addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0); + /* Calculate the offset for Y and C data in the buffer */ + vpif_calculate_offsets(ch); + + if ((ch->vpifparams.std_info.frm_fmt && + ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) + && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) + || (!ch->vpifparams.std_info.frm_fmt + && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { + vpif_err("conflict in field format and std format\n"); + return -EINVAL; + } + + /* clock settings */ + ret = + vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, + ch->vpifparams.std_info.hd_sd); + if (ret < 0) { + vpif_err("can't set clock\n"); + return ret; + } + + /* set the parameters and addresses */ + ret = vpif_set_video_params(vpif, ch->channel_id + 2); + if (ret < 0) + return ret; + + common->started = ret; + vpif_config_addr(ch, ret); + common->set_addr((addr + common->ytop_off), + (addr + common->ybtm_off), + (addr + common->ctop_off), + (addr + common->cbtm_off)); + + /* Set interrupt for both the fields in VPIF + Register enable channel in VPIF register */ + if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + channel2_intr_assert(); + channel2_intr_enable(1); + enable_channel2(1); + if (vpif_config_data->ch2_clip_en) + channel2_clipping_enable(1); + } + + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) + || (common->started == 2)) { + channel3_intr_assert(); + channel3_intr_enable(1); + enable_channel3(1); + if (vpif_config_data->ch3_clip_en) + channel3_clipping_enable(1); + } + channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; + + return 0; +} + +/* abort streaming and wait for last buffer */ +static int vpif_stop_streaming(struct vb2_queue *vq) +{ + struct vpif_fh *fh = vb2_get_drv_priv(vq); + struct channel_obj *ch = fh->channel; + struct common_obj *common; + + if (!vb2_is_streaming(vq)) + return 0; + + common = &ch->common[VPIF_VIDEO_INDEX]; + + /* release all active buffers */ + while (!list_empty(&common->dma_queue)) { + common->next_frm = list_entry(common->dma_queue.next, + struct vpif_disp_buffer, list); + list_del(&common->next_frm->list); + vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR); + } + + return 0; +} + +static struct vb2_ops video_qops = { + .queue_setup = vpif_buffer_queue_setup, + .wait_prepare = vpif_wait_prepare, + .wait_finish = vpif_wait_finish, + .buf_init = vpif_buffer_init, + .buf_prepare = vpif_buffer_prepare, + .start_streaming = vpif_start_streaming, + .stop_streaming = vpif_stop_streaming, + .buf_cleanup = vpif_buf_cleanup, + .buf_queue = vpif_buffer_queue, +}; + static void process_progressive_mode(struct common_obj *common) { unsigned long addr = 0; /* Get the next buffer from buffer queue */ common->next_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); + struct vpif_disp_buffer, list); /* Remove that buffer from the buffer queue */ - list_del(&common->next_frm->queue); + list_del(&common->next_frm->list); /* Mark status of the buffer as active */ - common->next_frm->state = VIDEOBUF_ACTIVE; + common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; /* Set top and bottom field addrs in VPIF registers */ - addr = videobuf_to_dma_contig(common->next_frm); + addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0); common->set_addr(addr + common->ytop_off, addr + common->ybtm_off, addr + common->ctop_off, @@ -271,11 +389,10 @@ static void process_interlaced_mode(int fid, struct common_obj *common) /* one frame is displayed If next frame is * available, release cur_frm and move on */ /* Copy frame display time */ - do_gettimeofday(&common->cur_frm->ts); + do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp); /* Change status of the cur_frm */ - common->cur_frm->state = VIDEOBUF_DONE; - /* unlock semaphore on cur_frm */ - wake_up_interruptible(&common->cur_frm->done); + vb2_buffer_done(&common->cur_frm->vb, + VB2_BUF_STATE_DONE); /* Make cur_frm pointing to next_frm */ common->cur_frm = common->next_frm; @@ -307,6 +424,9 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) int channel_id = 0; channel_id = *(int *)(dev_id); + if (!vpif_intr_status(channel_id + 2)) + return IRQ_NONE; + ch = dev->dev[channel_id]; field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; for (i = 0; i < VPIF_NUMOBJECTS; i++) { @@ -323,9 +443,10 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) if (!channel_first_int[i][channel_id]) { /* Mark status of the cur_frm to * done and unlock semaphore on it */ - do_gettimeofday(&common->cur_frm->ts); - common->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&common->cur_frm->done); + do_gettimeofday(&common->cur_frm->vb. + v4l2_buf.timestamp); + vb2_buffer_done(&common->cur_frm->vb, + VB2_BUF_STATE_DONE); /* Make cur_frm pointing to next_frm */ common->cur_frm = common->next_frm; } @@ -443,10 +564,7 @@ static void vpif_calculate_offsets(struct channel_obj *ch) vid_ch->buf_field = common->fmt.fmt.pix.field; } - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = common->fmt.fmt.pix.sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; + sizeimage = common->fmt.fmt.pix.sizeimage; hpitch = common->fmt.fmt.pix.bytesperline; vpitch = sizeimage / (hpitch * 2); @@ -523,10 +641,7 @@ static int vpif_check_format(struct channel_obj *ch, if (pixfmt->bytesperline <= 0) goto invalid_pitch_exit; - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = pixfmt->sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; + sizeimage = pixfmt->sizeimage; if (vpif_update_resolution(ch)) return -EINVAL; @@ -583,7 +698,7 @@ static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) vpif_dbg(2, debug, "vpif_mmap\n"); - return videobuf_mmap_mapper(&common->buffer_queue, vma); + return vb2_mmap(&common->buffer_queue, vma); } /* @@ -596,7 +711,7 @@ static unsigned int vpif_poll(struct file *filep, poll_table *wait) struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; if (common->started) - return videobuf_poll_stream(filep, &common->buffer_queue, wait); + return vb2_poll(&common->buffer_queue, filep, wait); return 0; } @@ -665,9 +780,11 @@ static int vpif_release(struct file *filep) channel3_intr_enable(0); } common->started = 0; + /* Free buffers allocated */ - videobuf_queue_cancel(&common->buffer_queue); - videobuf_mmap_free(&common->buffer_queue); + vb2_queue_release(&common->buffer_queue); + vb2_dma_contig_cleanup_ctx(common->alloc_ctx); + common->numbuffers = config_params.numbuffers[ch->channel_id]; } @@ -806,6 +923,7 @@ static int vpif_reqbufs(struct file *file, void *priv, struct channel_obj *ch = fh->channel; struct common_obj *common; enum v4l2_field field; + struct vb2_queue *q; u8 index = 0; /* This file handle has not initialized the channel, @@ -825,9 +943,8 @@ static int vpif_reqbufs(struct file *file, void *priv, common = &ch->common[index]; - if (common->fmt.type != reqbuf->type) + if (common->fmt.type != reqbuf->type || !vpif_dev) return -EINVAL; - if (0 != common->io_usrs) return -EBUSY; @@ -839,14 +956,21 @@ static int vpif_reqbufs(struct file *file, void *priv, } else { field = V4L2_VBI_INTERLACED; } + /* Initialize videobuf2 queue as per the buffer type */ + common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev); + if (!common->alloc_ctx) { + vpif_err("Failed to get the context\n"); + return -EINVAL; + } + q = &common->buffer_queue; + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = fh; + q->ops = &video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct vpif_disp_buffer); - /* Initialize videobuf queue as per the buffer type */ - videobuf_queue_dma_contig_init(&common->buffer_queue, - &video_qops, NULL, - &common->irqlock, - reqbuf->type, field, - sizeof(struct videobuf_buffer), fh, - &common->lock); + vb2_queue_init(q); /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; @@ -855,9 +979,8 @@ static int vpif_reqbufs(struct file *file, void *priv, /* Store type of memory requested in channel object */ common->memory = reqbuf->memory; INIT_LIST_HEAD(&common->dma_queue); - /* Allocate buffers */ - return videobuf_reqbufs(&common->buffer_queue, reqbuf); + return vb2_reqbufs(&common->buffer_queue, reqbuf); } static int vpif_querybuf(struct file *file, void *priv, @@ -870,22 +993,25 @@ static int vpif_querybuf(struct file *file, void *priv, if (common->fmt.type != tbuf->type) return -EINVAL; - return videobuf_querybuf(&common->buffer_queue, tbuf); + return vb2_querybuf(&common->buffer_queue, tbuf); } static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { + struct vpif_fh *fh = NULL; + struct channel_obj *ch = NULL; + struct common_obj *common = NULL; - struct vpif_fh *fh = priv; - struct channel_obj *ch = fh->channel; - struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct v4l2_buffer tbuf = *buf; - struct videobuf_buffer *buf1; - unsigned long addr = 0; - unsigned long flags; - int ret = 0; + if (!buf || !priv) + return -EINVAL; + + fh = priv; + ch = fh->channel; + if (!ch) + return -EINVAL; - if (common->fmt.type != tbuf.type) + common = &(ch->common[VPIF_VIDEO_INDEX]); + if (common->fmt.type != buf->type) return -EINVAL; if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { @@ -893,73 +1019,7 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return -EACCES; } - if (!(list_empty(&common->dma_queue)) || - (common->cur_frm != common->next_frm) || - !(common->started) || - (common->started && (0 == ch->field_id))) - return videobuf_qbuf(&common->buffer_queue, buf); - - /* bufferqueue is empty store buffer address in VPIF registers */ - mutex_lock(&common->buffer_queue.vb_lock); - buf1 = common->buffer_queue.bufs[tbuf.index]; - if (buf1->memory != tbuf.memory) { - vpif_err("invalid buffer type\n"); - goto qbuf_exit; - } - - if ((buf1->state == VIDEOBUF_QUEUED) || - (buf1->state == VIDEOBUF_ACTIVE)) { - vpif_err("invalid state\n"); - goto qbuf_exit; - } - - switch (buf1->memory) { - case V4L2_MEMORY_MMAP: - if (buf1->baddr == 0) - goto qbuf_exit; - break; - - case V4L2_MEMORY_USERPTR: - if (tbuf.length < buf1->bsize) - goto qbuf_exit; - - if ((VIDEOBUF_NEEDS_INIT != buf1->state) - && (buf1->baddr != tbuf.m.userptr)) { - vpif_buffer_release(&common->buffer_queue, buf1); - buf1->baddr = tbuf.m.userptr; - } - break; - - default: - goto qbuf_exit; - } - - local_irq_save(flags); - ret = vpif_buffer_prepare(&common->buffer_queue, buf1, - common->buffer_queue.field); - if (ret < 0) { - local_irq_restore(flags); - goto qbuf_exit; - } - - buf1->state = VIDEOBUF_ACTIVE; - addr = buf1->boff; - common->next_frm = buf1; - if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { - common->set_addr((addr + common->ytop_off), - (addr + common->ybtm_off), - (addr + common->ctop_off), - (addr + common->cbtm_off)); - } - - local_irq_restore(flags); - list_add_tail(&buf1->stream, &common->buffer_queue.stream); - mutex_unlock(&common->buffer_queue.vb_lock); - return 0; - -qbuf_exit: - mutex_unlock(&common->buffer_queue.vb_lock); - return -EINVAL; + return vb2_qbuf(&common->buffer_queue, buf); } static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) @@ -969,7 +1029,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; int ret = 0; - if (!(*std_id & DM646X_V4L2_STD)) + if (!(*std_id & VPIF_V4L2_STD)) return -EINVAL; if (common->started) { @@ -1026,7 +1086,7 @@ static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - return videobuf_dqbuf(&common->buffer_queue, p, + return vb2_dqbuf(&common->buffer_queue, p, (file->f_flags & O_NONBLOCK)); } @@ -1037,10 +1097,6 @@ static int vpif_streamon(struct file *file, void *priv, struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; - struct vpif_params *vpif = &ch->vpifparams; - struct vpif_display_config *vpif_config_data = - vpif_dev->platform_data; - unsigned long addr = 0; int ret = 0; if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -1072,82 +1128,13 @@ static int vpif_streamon(struct file *file, void *priv, if (ret < 0) return ret; - /* Call videobuf_streamon to start streaming in videobuf */ - ret = videobuf_streamon(&common->buffer_queue); + /* Call vb2_streamon to start streaming in videobuf2 */ + ret = vb2_streamon(&common->buffer_queue, buftype); if (ret < 0) { - vpif_err("videobuf_streamon\n"); + vpif_err("vb2_streamon\n"); return ret; } - /* If buffer queue is empty, return error */ - if (list_empty(&common->dma_queue)) { - vpif_err("buffer queue is empty\n"); - return -EIO; - } - - /* Get the next frame from the buffer queue */ - common->next_frm = common->cur_frm = - list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - - list_del(&common->cur_frm->queue); - /* Mark state of the current frame to active */ - common->cur_frm->state = VIDEOBUF_ACTIVE; - - /* Initialize field_id and started member */ - ch->field_id = 0; - common->started = 1; - if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - addr = common->cur_frm->boff; - /* Calculate the offset for Y and C data in the buffer */ - vpif_calculate_offsets(ch); - - if ((ch->vpifparams.std_info.frm_fmt && - ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) - && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) - || (!ch->vpifparams.std_info.frm_fmt - && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { - vpif_err("conflict in field format and std format\n"); - return -EINVAL; - } - - /* clock settings */ - ret = - vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, - ch->vpifparams.std_info.hd_sd); - if (ret < 0) { - vpif_err("can't set clock\n"); - return ret; - } - - /* set the parameters and addresses */ - ret = vpif_set_video_params(vpif, ch->channel_id + 2); - if (ret < 0) - return ret; - - common->started = ret; - vpif_config_addr(ch, ret); - common->set_addr((addr + common->ytop_off), - (addr + common->ybtm_off), - (addr + common->ctop_off), - (addr + common->cbtm_off)); - - /* Set interrupt for both the fields in VPIF - Register enable channel in VPIF register */ - if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - channel2_intr_assert(); - channel2_intr_enable(1); - enable_channel2(1); - } - - if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) - || (common->started == 2)) { - channel3_intr_assert(); - channel3_intr_enable(1); - enable_channel3(1); - } - channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; - } return ret; } @@ -1157,6 +1144,8 @@ static int vpif_streamoff(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct vpif_display_config *vpif_config_data = + vpif_dev->platform_data; if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { vpif_err("buffer type not supported\n"); @@ -1176,18 +1165,22 @@ static int vpif_streamoff(struct file *file, void *priv, if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* disable channel */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + if (vpif_config_data->ch2_clip_en) + channel2_clipping_enable(0); enable_channel2(0); channel2_intr_enable(0); } if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || (2 == common->started)) { + if (vpif_config_data->ch3_clip_en) + channel3_clipping_enable(0); enable_channel3(0); channel3_intr_enable(0); } } common->started = 0; - return videobuf_streamoff(&common->buffer_queue); + return vb2_streamoff(&common->buffer_queue, buftype); } static int vpif_cropcap(struct file *file, void *priv, @@ -1220,7 +1213,7 @@ static int vpif_enum_output(struct file *file, void *fh, strcpy(output->name, config->output[output->index]); output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->std = DM646X_V4L2_STD; + output->std = VPIF_V4L2_STD; return 0; } @@ -1605,7 +1598,7 @@ static struct video_device vpif_video_template = { .name = "vpif", .fops = &vpif_fops, .ioctl_ops = &vpif_ioctl_ops, - .tvnorms = DM646X_V4L2_STD, + .tvnorms = VPIF_V4L2_STD, .current_norm = V4L2_STD_625_50, }; @@ -1687,9 +1680,9 @@ static __init int vpif_probe(struct platform_device *pdev) struct video_device *vfd; struct resource *res; int subdev_count; + size_t size; vpif_dev = &pdev->dev; - err = initialize_vpif(); if (err) { @@ -1706,8 +1699,8 @@ static __init int vpif_probe(struct platform_device *pdev) k = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { - if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, - "DM646x_Display", + if (request_irq(i, vpif_channel_isr, IRQF_SHARED, + "VPIF_Display", (void *)(&vpif_obj.dev[k]->channel_id))) { err = -EBUSY; goto vpif_int_err; @@ -1737,13 +1730,31 @@ static __init int vpif_probe(struct platform_device *pdev) vfd->v4l2_dev = &vpif_obj.v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFDisplay_DRIVER_V%s", + "VPIF_Display_DRIVER_V%s", VPIF_DISPLAY_VERSION); /* Set video_dev to the video device */ ch->video_dev = vfd; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + size = resource_size(res); + /* The resources are divided into two equal memory and when + * we have HD output we can add them together + */ + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + + /* only enabled if second resource exists */ + config_params.video_limit[ch->channel_id] = 0; + if (size) + config_params.video_limit[ch->channel_id] = + size/2; + } + } + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { ch = vpif_obj.dev[j]; /* Initialize field of the channel objects */ @@ -1823,7 +1834,7 @@ static __init int vpif_probe(struct platform_device *pdev) } v4l2_info(&vpif_obj.v4l2_dev, - "DM646x VPIF display driver initialized\n"); + " VPIF display driver initialized\n"); return 0; probe_subdev_out: @@ -1871,10 +1882,81 @@ static int vpif_remove(struct platform_device *device) return 0; } +#ifdef CONFIG_PM +static int vpif_suspend(struct device *dev) +{ + struct common_obj *common; + struct channel_obj *ch; + int i; + + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); + if (atomic_read(&ch->usrs) && common->io_usrs) { + /* Disable channel */ + if (ch->channel_id == VPIF_CHANNEL2_VIDEO) { + enable_channel2(0); + channel2_intr_enable(0); + } + if (ch->channel_id == VPIF_CHANNEL3_VIDEO || + common->started == 2) { + enable_channel3(0); + channel3_intr_enable(0); + } + } + mutex_unlock(&common->lock); + } + + return 0; +} + +static int vpif_resume(struct device *dev) +{ + + struct common_obj *common; + struct channel_obj *ch; + int i; + + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); + if (atomic_read(&ch->usrs) && common->io_usrs) { + /* Enable channel */ + if (ch->channel_id == VPIF_CHANNEL2_VIDEO) { + enable_channel2(1); + channel2_intr_enable(1); + } + if (ch->channel_id == VPIF_CHANNEL3_VIDEO || + common->started == 2) { + enable_channel3(1); + channel3_intr_enable(1); + } + } + mutex_unlock(&common->lock); + } + + return 0; +} + +static const struct dev_pm_ops vpif_pm = { + .suspend = vpif_suspend, + .resume = vpif_resume, +}; + +#define vpif_pm_ops (&vpif_pm) +#else +#define vpif_pm_ops NULL +#endif + static __refdata struct platform_driver vpif_driver = { .driver = { .name = "vpif_display", .owner = THIS_MODULE, + .pm = vpif_pm_ops, }, .probe = vpif_probe, .remove = vpif_remove, diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h index 56879d1a0684..8967ffb44058 100644 --- a/drivers/media/video/davinci/vpif_display.h +++ b/drivers/media/video/davinci/vpif_display.h @@ -1,5 +1,5 @@ /* - * DM646x display header file + * VPIF display header file * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ * @@ -21,7 +21,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-device.h> #include <media/videobuf-core.h> -#include <media/videobuf-dma-contig.h> +#include <media/videobuf2-dma-contig.h> #include <media/davinci/vpif_types.h> #include "vpif.h" @@ -73,21 +73,29 @@ struct vbi_obj { * vbi data */ }; +struct vpif_disp_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + struct common_obj { /* Buffer specific parameters */ u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for * storing frames */ u32 numbuffers; /* number of buffers */ - struct videobuf_buffer *cur_frm; /* Pointer pointing to current - * videobuf_buffer */ - struct videobuf_buffer *next_frm; /* Pointer pointing to next - * videobuf_buffer */ + struct vpif_disp_buffer *cur_frm; /* Pointer pointing to current + * vb2_buffer */ + struct vpif_disp_buffer *next_frm; /* Pointer pointing to next + * vb2_buffer */ enum v4l2_memory memory; /* This field keeps track of * type of buffer exchange * method user has selected */ struct v4l2_format fmt; /* Used to store the format */ - struct videobuf_queue buffer_queue; /* Buffer queue used in + struct vb2_queue buffer_queue; /* Buffer queue used in * video-buf */ + /* allocator-specific contexts for each plane */ + struct vb2_alloc_ctx *alloc_ctx; + struct list_head dma_queue; /* Queue of filled frames */ spinlock_t irqlock; /* Used in video-buf */ @@ -158,6 +166,7 @@ struct vpif_config_params { u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS]; + u32 video_limit[VPIF_DISPLAY_NUM_CHANNELS]; u8 min_numbuffers; }; diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index d7e2a3dc5525..07dc594e79f0 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -42,6 +42,7 @@ #include <sound/initval.h> #include <sound/control.h> #include <sound/tlv.h> +#include <sound/ac97_codec.h> #include <media/v4l2-common.h> #include "em28xx.h" @@ -679,19 +680,19 @@ static int em28xx_audio_init(struct em28xx *dev) INIT_WORK(&dev->wq_trigger, audio_trigger); if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { - em28xx_cvol_new(card, dev, "Video", AC97_VIDEO_VOL); - em28xx_cvol_new(card, dev, "Line In", AC97_LINEIN_VOL); - em28xx_cvol_new(card, dev, "Phone", AC97_PHONE_VOL); - em28xx_cvol_new(card, dev, "Microphone", AC97_PHONE_VOL); - em28xx_cvol_new(card, dev, "CD", AC97_CD_VOL); - em28xx_cvol_new(card, dev, "AUX", AC97_AUX_VOL); - em28xx_cvol_new(card, dev, "PCM", AC97_PCM_OUT_VOL); - - em28xx_cvol_new(card, dev, "Master", AC97_MASTER_VOL); - em28xx_cvol_new(card, dev, "Line", AC97_LINE_LEVEL_VOL); - em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO_VOL); - em28xx_cvol_new(card, dev, "LFE", AC97_LFE_MASTER_VOL); - em28xx_cvol_new(card, dev, "Surround", AC97_SURR_MASTER_VOL); + em28xx_cvol_new(card, dev, "Video", AC97_VIDEO); + em28xx_cvol_new(card, dev, "Line In", AC97_LINE); + em28xx_cvol_new(card, dev, "Phone", AC97_PHONE); + em28xx_cvol_new(card, dev, "Microphone", AC97_MIC); + em28xx_cvol_new(card, dev, "CD", AC97_CD); + em28xx_cvol_new(card, dev, "AUX", AC97_AUX); + em28xx_cvol_new(card, dev, "PCM", AC97_PCM); + + em28xx_cvol_new(card, dev, "Master", AC97_MASTER); + em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE); + em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO); + em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER); + em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER); } err = snd_card_register(card); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 92da7c28b6f0..ca62b9981380 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -975,12 +975,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Cinergy HTC Stick", .has_dvb = 1, .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, -#if 0 - .tuner_type = TUNER_PHILIPS_TDA8290, - .tuner_addr = 0x41, - .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */ - .tuner_gpio = terratec_h5_gpio, -#endif + .tuner_type = TUNER_ABSENT, .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, @@ -2893,7 +2888,7 @@ static void request_module_async(struct work_struct *work) if (dev->board.has_dvb) request_module("em28xx-dvb"); - if (dev->board.has_ir_i2c && !disable_ir) + if (dev->board.ir_codes && !disable_ir) request_module("em28xx-rc"); } diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 5717bdee8f1b..de2cb20ad2cc 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/usb.h> #include <linux/vmalloc.h> +#include <sound/ac97_codec.h> #include <media/v4l2-common.h> #include "em28xx.h" @@ -326,13 +327,13 @@ struct em28xx_vol_itable { }; static struct em28xx_vol_itable inputs[] = { - { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL }, - { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL }, - { EM28XX_AMUX_PHONE, AC97_PHONE_VOL }, - { EM28XX_AMUX_MIC, AC97_MIC_VOL }, - { EM28XX_AMUX_CD, AC97_CD_VOL }, - { EM28XX_AMUX_AUX, AC97_AUX_VOL }, - { EM28XX_AMUX_PCM_OUT, AC97_PCM_OUT_VOL }, + { EM28XX_AMUX_VIDEO, AC97_VIDEO }, + { EM28XX_AMUX_LINE_IN, AC97_LINE }, + { EM28XX_AMUX_PHONE, AC97_PHONE }, + { EM28XX_AMUX_MIC, AC97_MIC }, + { EM28XX_AMUX_CD, AC97_CD }, + { EM28XX_AMUX_AUX, AC97_AUX }, + { EM28XX_AMUX_PCM_OUT, AC97_PCM }, }; static int set_ac97_input(struct em28xx *dev) @@ -415,11 +416,11 @@ struct em28xx_vol_otable { }; static const struct em28xx_vol_otable outputs[] = { - { EM28XX_AOUT_MASTER, AC97_MASTER_VOL }, - { EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL }, - { EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL }, - { EM28XX_AOUT_LFE, AC97_LFE_MASTER_VOL }, - { EM28XX_AOUT_SURR, AC97_SURR_MASTER_VOL }, + { EM28XX_AOUT_MASTER, AC97_MASTER }, + { EM28XX_AOUT_LINE, AC97_HEADPHONE }, + { EM28XX_AOUT_MONO, AC97_MASTER_MONO }, + { EM28XX_AOUT_LFE, AC97_CENTER_LFE_MASTER }, + { EM28XX_AOUT_SURR, AC97_SURROUND_MASTER }, }; int em28xx_audio_analog_set(struct em28xx *dev) @@ -459,9 +460,9 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { int vol; - em28xx_write_ac97(dev, AC97_POWER_DOWN_CTRL, 0x4200); - em28xx_write_ac97(dev, AC97_EXT_AUD_CTRL, 0x0031); - em28xx_write_ac97(dev, AC97_PCM_IN_SRATE, 0xbb80); + em28xx_write_ac97(dev, AC97_POWERDOWN, 0x4200); + em28xx_write_ac97(dev, AC97_EXTENDED_STATUS, 0x0031); + em28xx_write_ac97(dev, AC97_PCM_LR_ADC_RATE, 0xbb80); /* LSB: left channel - both channels with the same level */ vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8); @@ -487,7 +488,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) channels */ sel |= (sel << 8); - em28xx_write_ac97(dev, AC97_RECORD_SELECT, sel); + em28xx_write_ac97(dev, AC97_REC_SEL, sel); } } diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index 16410ac20092..a16531fa937a 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -310,31 +310,47 @@ static struct drxd_config em28xx_drxd = { .disable_i2c_gate_ctrl = 1, }; -struct drxk_config terratec_h5_drxk = { +static struct drxk_config terratec_h5_drxk = { .adr = 0x29, .single_master = 1, .no_i2c_bridge = 1, .microcode_name = "dvb-usb-terratec-h5-drxk.fw", + .qam_demod_parameter_count = 2, }; -struct drxk_config hauppauge_930c_drxk = { +static struct drxk_config hauppauge_930c_drxk = { .adr = 0x29, .single_master = 1, .no_i2c_bridge = 1, .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw", .chunk_size = 56, + .qam_demod_parameter_count = 2, }; -struct drxk_config maxmedia_ub425_tc_drxk = { +struct drxk_config terratec_htc_stick_drxk = { .adr = 0x29, .single_master = 1, .no_i2c_bridge = 1, + .microcode_name = "dvb-usb-terratec-htc-stick-drxk.fw", + .chunk_size = 54, + .qam_demod_parameter_count = 2, + /* Required for the antenna_gpio to disable LNA. */ + .antenna_dvbt = true, + /* The windows driver uses the same. This will disable LNA. */ + .antenna_gpio = 0x6, }; -struct drxk_config pctv_520e_drxk = { +static struct drxk_config maxmedia_ub425_tc_drxk = { + .adr = 0x29, + .single_master = 1, + .no_i2c_bridge = 1, +}; + +static struct drxk_config pctv_520e_drxk = { .adr = 0x29, .single_master = 1, .microcode_name = "dvb-demod-drxk-pctv.fw", + .qam_demod_parameter_count = 2, .chunk_size = 58, .antenna_dvbt = true, /* disable LNA */ .antenna_gpio = (1 << 2), /* disable LNA */ @@ -473,6 +489,57 @@ static void terratec_h5_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_h5_end); }; +static void terratec_htc_stick_init(struct em28xx *dev) +{ + int i; + + /* + * GPIO configuration: + * 0xff: unknown (does not affect DVB-T). + * 0xf6: DRX-K (demodulator). + * 0xe6: unknown (does not affect DVB-T). + * 0xb6: unknown (does not affect DVB-T). + */ + struct em28xx_reg_seq terratec_htc_stick_init[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM2874_R80_GPIO, 0xf6, 0xff, 100}, + {EM2874_R80_GPIO, 0xe6, 0xff, 50}, + {EM2874_R80_GPIO, 0xf6, 0xff, 100}, + { -1, -1, -1, -1}, + }; + struct em28xx_reg_seq terratec_htc_stick_end[] = { + {EM2874_R80_GPIO, 0xb6, 0xff, 100}, + {EM2874_R80_GPIO, 0xf6, 0xff, 50}, + { -1, -1, -1, -1}, + }; + + /* Init the analog decoder? */ + struct { + unsigned char r[4]; + int len; + } regs[] = { + {{ 0x06, 0x02, 0x00, 0x31 }, 4}, + {{ 0x01, 0x02 }, 2}, + {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0xff, 0xaf }, 4}, + }; + + em28xx_gpio_set(dev, terratec_htc_stick_init); + + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); + msleep(10); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); + msleep(10); + + dev->i2c_client.addr = 0x82 >> 1; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + + em28xx_gpio_set(dev, terratec_htc_stick_end); +}; + static void pctv_520e_init(struct em28xx *dev) { /* @@ -944,7 +1011,6 @@ static int em28xx_dvb_init(struct em28xx *dev) break; } case EM2884_BOARD_TERRATEC_H5: - case EM2884_BOARD_CINERGY_HTC_STICK: terratec_h5_init(dev); dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap); @@ -1021,6 +1087,25 @@ static int em28xx_dvb_init(struct em28xx *dev) } } break; + case EM2884_BOARD_CINERGY_HTC_STICK: + terratec_htc_stick_init(dev); + + /* attach demodulator */ + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk, + &dev->i2c_adap); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + + /* Attach the demodulator. */ + if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + &dev->i2c_adap, + &em28xx_cxd2820r_tda18271_config)) { + result = -EINVAL; + goto out_free; + } + break; default: em28xx_errdev("/2: The frontend of your DVB/ATSC card" " isn't supported yet\n"); diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 185db65b766e..1683bd9d51ee 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -475,6 +475,7 @@ static struct i2c_client em28xx_client_template = { */ static char *i2c_devs[128] = { [0x4a >> 1] = "saa7113h", + [0x52 >> 1] = "drxk", [0x60 >> 1] = "remote IR sensor", [0x8e >> 1] = "remote IR sensor", [0x86 >> 1] = "tda9887", diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 5e30c4f3f248..97d36b4f19db 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -345,7 +345,7 @@ static void em28xx_ir_stop(struct rc_dev *rc) cancel_delayed_work_sync(&ir->work); } -int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) +static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) { int rc = 0; struct em28xx_IR *ir = rc_dev->priv; diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index 2f6268505726..6ff368297f6e 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h @@ -211,58 +211,9 @@ enum em28xx_chip_id { }; /* - * Registers used by em202 and other AC97 chips + * Registers used by em202 */ -/* Standard AC97 registers */ -#define AC97_RESET 0x00 - - /* Output volumes */ -#define AC97_MASTER_VOL 0x02 -#define AC97_LINE_LEVEL_VOL 0x04 /* Some devices use for headphones */ -#define AC97_MASTER_MONO_VOL 0x06 - - /* Input volumes */ -#define AC97_PC_BEEP_VOL 0x0a -#define AC97_PHONE_VOL 0x0c -#define AC97_MIC_VOL 0x0e -#define AC97_LINEIN_VOL 0x10 -#define AC97_CD_VOL 0x12 -#define AC97_VIDEO_VOL 0x14 -#define AC97_AUX_VOL 0x16 -#define AC97_PCM_OUT_VOL 0x18 - - /* capture registers */ -#define AC97_RECORD_SELECT 0x1a -#define AC97_RECORD_GAIN 0x1c - - /* control registers */ -#define AC97_GENERAL_PURPOSE 0x20 -#define AC97_3D_CTRL 0x22 -#define AC97_AUD_INT_AND_PAG 0x24 -#define AC97_POWER_DOWN_CTRL 0x26 -#define AC97_EXT_AUD_ID 0x28 -#define AC97_EXT_AUD_CTRL 0x2a - -/* Supported rate varies for each AC97 device - if write an unsupported value, it will return the closest one - */ -#define AC97_PCM_OUT_FRONT_SRATE 0x2c -#define AC97_PCM_OUT_SURR_SRATE 0x2e -#define AC97_PCM_OUT_LFE_SRATE 0x30 -#define AC97_PCM_IN_SRATE 0x32 - - /* For devices with more than 2 channels, extra output volumes */ -#define AC97_LFE_MASTER_VOL 0x36 -#define AC97_SURR_MASTER_VOL 0x38 - - /* Digital SPDIF output control */ -#define AC97_SPDIF_OUT_CTRL 0x3a - - /* Vendor ID identifier */ -#define AC97_VENDOR_ID1 0x7c -#define AC97_VENDOR_ID2 0x7e - /* EMP202 vendor registers */ #define EM202_EXT_MODEM_CTRL 0x3e #define EM202_GPIO_CONF 0x4c diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c index 9769f17915c0..352f32190e68 100644 --- a/drivers/media/video/gspca/benq.c +++ b/drivers/media/video/gspca/benq.c @@ -33,10 +33,6 @@ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ }; -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[] = { -}; - static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, @@ -256,8 +252,6 @@ static void sd_isoc_irq(struct urb *urb) /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, .start = sd_start, @@ -288,6 +282,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index f39fee0fd10f..c9052f20435e 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -31,74 +31,18 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver"); MODULE_LICENSE("GPL"); +#define QUALITY 50 + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - u8 quality; -#define QUALITY_MIN 30 -#define QUALITY_MAX 60 -#define QUALITY_DEF 40 + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + struct v4l2_ctrl *sat; u8 jpeg_hdr[JPEG_HDR_SZ]; }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 0xd4 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0x0a, - .maximum = 0x1f, - .step = 1, -#define CONTRAST_DEF 0x0c - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 7, - .step = 1, -#define COLOR_DEF 3 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, @@ -817,17 +761,11 @@ static void cx11646_init1(struct gspca_dev *gspca_dev) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; cam = &gspca_dev->cam; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->quality = QUALITY_DEF; return 0; } @@ -849,7 +787,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + jpeg_set_qual(sd->jpeg_hdr, QUALITY); cx11646_initsize(gspca_dev); cx11646_fw(gspca_dev); @@ -903,142 +841,99 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val, s32 sat) { - struct sd *sd = (struct sd *) gspca_dev; __u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 }; __u8 reg51c[2]; - __u8 bright; - __u8 colors; - bright = sd->brightness; - regE5cbx[2] = bright; + regE5cbx[2] = val; reg_w(gspca_dev, 0x00e5, regE5cbx, 8); reg_r(gspca_dev, 0x00e8, 8); reg_w(gspca_dev, 0x00e5, regE5c, 4); reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ - colors = sd->colors; reg51c[0] = 0x77; - reg51c[1] = colors; + reg51c[1] = sat; reg_w(gspca_dev, 0x0051, reg51c, 2); reg_w(gspca_dev, 0x0010, reg10, 2); reg_w_val(gspca_dev, 0x0070, reg70); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val, s32 sat) { - struct sd *sd = (struct sd *) gspca_dev; __u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 }; /* seem MSB */ /* __u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01}; * LSB */ __u8 reg51c[2]; - regE5acx[2] = sd->contrast; + regE5acx[2] = val; reg_w(gspca_dev, 0x00e5, regE5acx, 4); reg_r(gspca_dev, 0x00e8, 1); /* 0x00 */ reg51c[0] = 0x77; - reg51c[1] = sd->colors; + reg51c[1] = sat; reg_w(gspca_dev, 0x0051, reg51c, 2); reg_w(gspca_dev, 0x0010, reg10, 2); reg_w_val(gspca_dev, 0x0070, reg70); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; - *val = sd->contrast; - return 0; -} + gspca_dev->usb_err = 0; -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - sd->colors = val; - if (gspca_dev->streaming) { - setbrightness(gspca_dev); - setcontrast(gspca_dev); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val, sd->sat->cur.val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val, sd->sat->cur.val); + break; + case V4L2_CID_SATURATION: + setbrightness(gspca_dev, sd->brightness->cur.val, ctrl->val); + setcontrast(gspca_dev, sd->contrast->cur.val, ctrl->val); + break; } - return 0; + return gspca_dev->usb_err; } -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return 0; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 3); + sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 0xd4); + sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0x0a, 0x1f, 1, 0x0c); + sd->sat = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 7, 1, 3); + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, }; /* -- module initialisation -- */ @@ -1064,6 +959,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index 8f33bbd091ad..2499a881d9a3 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c @@ -225,6 +225,15 @@ MODULE_LICENSE("GPL"); #define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \ sd->params.version.firmwareRevision == (y)) +#define CPIA1_CID_COMP_TARGET (V4L2_CTRL_CLASS_USER + 0x1000) +#define BRIGHTNESS_DEF 50 +#define CONTRAST_DEF 48 +#define SATURATION_DEF 50 +#define FREQ_DEF V4L2_CID_POWER_LINE_FREQUENCY_50HZ +#define ILLUMINATORS_1_DEF 0 +#define ILLUMINATORS_2_DEF 0 +#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY + /* Developer's Guide Table 5 p 3-34 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ static u8 flicker_jumps[2][2][4] = @@ -360,135 +369,9 @@ struct sd { atomic_t fps; int exposure_count; u8 exposure_status; + struct v4l2_ctrl *freq; u8 mainsFreq; /* 0 = 50hz, 1 = 60hz */ u8 first_frame; - u8 freq; -}; - -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { -#define BRIGHTNESS_IDX 0 - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 100, - .step = 1, -#define BRIGHTNESS_DEF 50 - .default_value = BRIGHTNESS_DEF, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define CONTRAST_IDX 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 96, - .step = 8, -#define CONTRAST_DEF 48 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SATURATION_IDX 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 100, - .step = 1, -#define SATURATION_DEF 50 - .default_value = SATURATION_DEF, - }, - .set = sd_setsaturation, - .get = sd_getsaturation, - }, -#define POWER_LINE_FREQUENCY_IDX 3 - { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, -#define FREQ_DEF 1 - .default_value = FREQ_DEF, - }, - .set = sd_setfreq, - .get = sd_getfreq, - }, -#define ILLUMINATORS_1_IDX 4 - { - { - .id = V4L2_CID_ILLUMINATORS_1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Illuminator 1", - .minimum = 0, - .maximum = 1, - .step = 1, -#define ILLUMINATORS_1_DEF 0 - .default_value = ILLUMINATORS_1_DEF, - }, - .set = sd_setilluminator1, - .get = sd_getilluminator1, - }, -#define ILLUMINATORS_2_IDX 5 - { - { - .id = V4L2_CID_ILLUMINATORS_2, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Illuminator 2", - .minimum = 0, - .maximum = 1, - .step = 1, -#define ILLUMINATORS_2_DEF 0 - .default_value = ILLUMINATORS_2_DEF, - }, - .set = sd_setilluminator2, - .get = sd_getilluminator2, - }, -#define COMP_TARGET_IDX 6 - { - { -#define V4L2_CID_COMP_TARGET V4L2_CID_PRIVATE_BASE - .id = V4L2_CID_COMP_TARGET, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Compression Target", - .minimum = 0, - .maximum = 1, - .step = 1, -#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY - .default_value = COMP_TARGET_DEF, - }, - .set = sd_setcomptarget, - .get = sd_getcomptarget, - }, }; static const struct v4l2_pix_format mode[] = { @@ -770,15 +653,6 @@ static void reset_camera_params(struct gspca_dev *gspca_dev) params->apcor.gain2 = 0x16; params->apcor.gain4 = 0x24; params->apcor.gain8 = 0x34; - params->flickerControl.flickerMode = 0; - params->flickerControl.disabled = 1; - - params->flickerControl.coarseJump = - flicker_jumps[sd->mainsFreq] - [params->sensorFps.baserate] - [params->sensorFps.divisor]; - params->flickerControl.allowableOverExposure = - find_over_exposure(params->colourParams.brightness); params->vlOffset.gain1 = 20; params->vlOffset.gain2 = 24; params->vlOffset.gain4 = 26; @@ -798,6 +672,15 @@ static void reset_camera_params(struct gspca_dev *gspca_dev) params->sensorFps.divisor = 1; params->sensorFps.baserate = 1; + params->flickerControl.flickerMode = 0; + params->flickerControl.disabled = 1; + params->flickerControl.coarseJump = + flicker_jumps[sd->mainsFreq] + [params->sensorFps.baserate] + [params->sensorFps.divisor]; + params->flickerControl.allowableOverExposure = + find_over_exposure(params->colourParams.brightness); + params->yuvThreshold.yThreshold = 6; /* From windows driver */ params->yuvThreshold.uvThreshold = 6; /* From windows driver */ @@ -1110,9 +993,6 @@ static int command_setlights(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int ret, p1, p2; - if (!sd->params.qx3.qx3_detected) - return 0; - p1 = (sd->params.qx3.bottomlight == 0) << 1; p2 = (sd->params.qx3.toplight == 0) << 3; @@ -1551,8 +1431,10 @@ static void restart_flicker(struct gspca_dev *gspca_dev) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { + struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; + sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ; reset_camera_params(gspca_dev); PDEBUG(D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)", @@ -1562,8 +1444,25 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = mode; cam->nmodes = ARRAY_SIZE(mode); - sd_setfreq(gspca_dev, FREQ_DEF); + goto_low_power(gspca_dev); + /* Check the firmware version. */ + sd->params.version.firmwareVersion = 0; + get_version_information(gspca_dev); + if (sd->params.version.firmwareVersion != 1) { + PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)", + sd->params.version.firmwareVersion); + return -ENODEV; + } + /* A bug in firmware 1-02 limits gainMode to 2 */ + if (sd->params.version.firmwareRevision <= 2 && + sd->params.exposure.gainMode > 2) { + sd->params.exposure.gainMode = 2; + } + + /* set QX3 detected flag */ + sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 && + sd->params.pnpID.product == 0x0001); return 0; } @@ -1602,21 +1501,6 @@ static int sd_start(struct gspca_dev *gspca_dev) /* Check the firmware version. */ sd->params.version.firmwareVersion = 0; get_version_information(gspca_dev); - if (sd->params.version.firmwareVersion != 1) { - PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)", - sd->params.version.firmwareVersion); - return -ENODEV; - } - - /* A bug in firmware 1-02 limits gainMode to 2 */ - if (sd->params.version.firmwareRevision <= 2 && - sd->params.exposure.gainMode > 2) { - sd->params.exposure.gainMode = 2; - } - - /* set QX3 detected flag */ - sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 && - sd->params.pnpID.product == 0x0001); /* The fatal error checking should be done after * the camera powers up (developer's guide p 3-38) */ @@ -1785,9 +1669,6 @@ static int sd_init(struct gspca_dev *gspca_dev) or disable the illuminator controls, if this isn't a QX3 */ if (sd->params.qx3.qx3_detected) command_setlights(gspca_dev); - else - gspca_dev->ctrl_dis |= - ((1 << ILLUMINATORS_1_IDX) | (1 << ILLUMINATORS_2_IDX)); sd_stopN(gspca_dev); @@ -1871,235 +1752,123 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev) do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - sd->params.colourParams.brightness = val; - sd->params.flickerControl.allowableOverExposure = - find_over_exposure(sd->params.colourParams.brightness); - if (gspca_dev->streaming) { - ret = command_setcolourparams(gspca_dev); - if (ret) - return ret; - return command_setflickerctrl(gspca_dev); - } - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->params.colourParams.brightness; - return 0; -} + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; + gspca_dev->usb_err = 0; - sd->params.colourParams.contrast = val; - if (gspca_dev->streaming) - return command_setcolourparams(gspca_dev); - - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->params.colourParams.contrast; - return 0; -} - -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->params.colourParams.saturation = val; - if (gspca_dev->streaming) - return command_setcolourparams(gspca_dev); - - return 0; -} - -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->params.colourParams.saturation; - return 0; -} - -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - int on; + if (!gspca_dev->streaming && ctrl->id != V4L2_CID_POWER_LINE_FREQUENCY) + return 0; - switch (val) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - on = 0; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + sd->params.colourParams.brightness = ctrl->val; + sd->params.flickerControl.allowableOverExposure = + find_over_exposure(sd->params.colourParams.brightness); + gspca_dev->usb_err = command_setcolourparams(gspca_dev); + if (!gspca_dev->usb_err) + gspca_dev->usb_err = command_setflickerctrl(gspca_dev); break; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - on = 1; - sd->mainsFreq = 0; + case V4L2_CID_CONTRAST: + sd->params.colourParams.contrast = ctrl->val; + gspca_dev->usb_err = command_setcolourparams(gspca_dev); break; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - on = 1; - sd->mainsFreq = 1; + case V4L2_CID_SATURATION: + sd->params.colourParams.saturation = ctrl->val; + gspca_dev->usb_err = command_setcolourparams(gspca_dev); break; - default: - return -EINVAL; - } - - sd->freq = val; - sd->params.flickerControl.coarseJump = - flicker_jumps[sd->mainsFreq] - [sd->params.sensorFps.baserate] - [sd->params.sensorFps.divisor]; - - return set_flicker(gspca_dev, on, gspca_dev->streaming); -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->freq; - return 0; -} - -static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->params.compressionTarget.frTargeting = val; - if (gspca_dev->streaming) - return command_setcompressiontarget(gspca_dev); - - return 0; -} - -static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->params.compressionTarget.frTargeting; - return 0; -} - -static int sd_setilluminator(struct gspca_dev *gspca_dev, __s32 val, int n) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - if (!sd->params.qx3.qx3_detected) - return -EINVAL; - - switch (n) { - case 1: - sd->params.qx3.bottomlight = val ? 1 : 0; + case V4L2_CID_POWER_LINE_FREQUENCY: + sd->mainsFreq = ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ; + sd->params.flickerControl.coarseJump = + flicker_jumps[sd->mainsFreq] + [sd->params.sensorFps.baserate] + [sd->params.sensorFps.divisor]; + + gspca_dev->usb_err = set_flicker(gspca_dev, + ctrl->val != V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, + gspca_dev->streaming); break; - case 2: - sd->params.qx3.toplight = val ? 1 : 0; + case V4L2_CID_ILLUMINATORS_1: + sd->params.qx3.bottomlight = ctrl->val; + gspca_dev->usb_err = command_setlights(gspca_dev); break; - default: - return -EINVAL; - } - - ret = command_setlights(gspca_dev); - if (ret && ret != -EINVAL) - ret = -EBUSY; - - return ret; -} - -static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val) -{ - return sd_setilluminator(gspca_dev, val, 1); -} - -static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val) -{ - return sd_setilluminator(gspca_dev, val, 2); -} - -static int sd_getilluminator(struct gspca_dev *gspca_dev, __s32 *val, int n) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (!sd->params.qx3.qx3_detected) - return -EINVAL; - - switch (n) { - case 1: - *val = sd->params.qx3.bottomlight; + case V4L2_CID_ILLUMINATORS_2: + sd->params.qx3.toplight = ctrl->val; + gspca_dev->usb_err = command_setlights(gspca_dev); break; - case 2: - *val = sd->params.qx3.toplight; + case CPIA1_CID_COMP_TARGET: + sd->params.compressionTarget.frTargeting = ctrl->val; + gspca_dev->usb_err = command_setcompressiontarget(gspca_dev); break; - default: - return -EINVAL; } - return 0; + return gspca_dev->usb_err; } -static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val) -{ - return sd_getilluminator(gspca_dev, val, 1); -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - return sd_getilluminator(gspca_dev, val, 2); -} + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + static const char * const comp_target_menu[] = { + "Quality", + "Framerate", + NULL + }; + static const struct v4l2_ctrl_config comp_target = { + .ops = &sd_ctrl_ops, + .id = CPIA1_CID_COMP_TARGET, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Compression Target", + .qmenu = comp_target_menu, + .max = 1, + .def = COMP_TARGET_DEF, + }; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 7); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 100, 1, BRIGHTNESS_DEF); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 96, 8, CONTRAST_DEF); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 100, 1, SATURATION_DEF); + sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, + FREQ_DEF); + if (sd->params.qx3.qx3_detected) { + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_ILLUMINATORS_1, 0, 1, 1, + ILLUMINATORS_1_DEF); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_ILLUMINATORS_2, 0, 1, 1, + ILLUMINATORS_2_DEF); + } + v4l2_ctrl_new_custom(hdl, &comp_target, NULL); -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - case V4L2_CID_COMP_TARGET: - switch (menu->index) { - case CPIA_COMPRESSION_TARGET_QUALITY: - strcpy((char *) menu->name, "Quality"); - return 0; - case CPIA_COMPRESSION_TARGET_FRAMERATE: - strcpy((char *) menu->name, "Framerate"); - return 0; - } - break; + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; } - return -EINVAL; + return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .dq_callback = sd_dq_callback, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) .other_input = 1, #endif @@ -2129,6 +1898,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 81a4adbd9f7c..38f68e11c3a2 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -32,9 +32,6 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned char brightness; - unsigned char contrast; - unsigned char colors; unsigned char autogain; char sensor; @@ -44,76 +41,6 @@ struct sd { #define AG_CNT_START 13 }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 1, - .maximum = 127, - .step = 1, -#define BRIGHTNESS_DEF 63 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define COLOR_IDX 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 15, - .step = 1, -#define COLOR_DEF 7 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 320, @@ -464,36 +391,31 @@ static void Et_init2(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */ } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; int i; - __u8 brightness = sd->brightness; for (i = 0; i < 4; i++) - reg_w_val(gspca_dev, ET_O_RED + i, brightness); + reg_w_val(gspca_dev, ET_O_RED + i, val); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; - __u8 contrast = sd->contrast; - memset(RGBG, contrast, sizeof(RGBG) - 2); + memset(RGBG, val, sizeof(RGBG) - 2); reg_w(gspca_dev, ET_G_RED, RGBG, 6); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; __u8 I2cc[] = { 0x05, 0x02, 0x02, 0x05, 0x0d }; __u8 i2cflags = 0x01; /* __u8 green = 0; */ - __u8 colors = sd->colors; - I2cc[3] = colors; /* red */ - I2cc[0] = 15 - colors; /* blue */ + I2cc[3] = val; /* red */ + I2cc[0] = 15 - val; /* blue */ /* green = 15 - ((((7*I2cc[0]) >> 2 ) + I2cc[3]) >> 1); */ /* I2cc[1] = I2cc[2] = green; */ if (sd->sensor == SENSOR_PAS106) { @@ -504,15 +426,16 @@ static void setcolors(struct gspca_dev *gspca_dev) I2cc[3], I2cc[0], green); */ } -static void getcolors(struct gspca_dev *gspca_dev) +static s32 getcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; if (sd->sensor == SENSOR_PAS106) { /* i2c_r(gspca_dev, PAS106_REG9); * blue */ i2c_r(gspca_dev, PAS106_REG9 + 3); /* red */ - sd->colors = gspca_dev->usb_buf[0] & 0x0f; + return gspca_dev->usb_buf[0] & 0x0f; } + return 0; } static void setautogain(struct gspca_dev *gspca_dev) @@ -622,8 +545,7 @@ static void Et_init1(struct gspca_dev *gspca_dev) i2c_w(gspca_dev, PAS106_REG7, I2c4, sizeof I2c4, 1); /* now set by fifo the whole colors setting */ reg_w(gspca_dev, ET_G_RED, GainRGBG, 6); - getcolors(gspca_dev); - setcolors(gspca_dev); + setcolors(gspca_dev, getcolors(gspca_dev)); } /* this function is called at probe time */ @@ -641,12 +563,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } else { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - gspca_dev->ctrl_dis = (1 << COLOR_IDX); } - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->autogain = AUTOGAIN_DEF; sd->ag_cnt = -1; return 0; } @@ -780,85 +697,68 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - if (gspca_dev->streaming) + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + sd->autogain = ctrl->val; setautogain(gspca_dev); - return 0; + break; + } + return gspca_dev->usb_err; } -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; - *val = sd->autogain; +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 1, 127, 1, 63); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 127); + if (sd->sensor == SENSOR_PAS106) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 15, 1, 7); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, @@ -892,6 +792,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c index 6e26c93b4656..c8f2201cc35a 100644 --- a/drivers/media/video/gspca/finepix.c +++ b/drivers/media/video/gspca/finepix.c @@ -299,6 +299,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index c549574c1c7e..ced3b71f14e5 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -521,6 +521,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 31721eadc597..d4e8343f5b10 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -930,6 +930,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) goto out; } gspca_dev->streaming = 1; + v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler); /* some bulk transfers are started by the subdriver */ if (gspca_dev->cam.bulk && gspca_dev->cam.bulk_nurbs == 0) @@ -1049,12 +1050,6 @@ static int vidioc_g_register(struct file *file, void *priv, { struct gspca_dev *gspca_dev = video_drvdata(file); - if (!gspca_dev->sd_desc->get_chip_ident) - return -ENOTTY; - - if (!gspca_dev->sd_desc->get_register) - return -ENOTTY; - gspca_dev->usb_err = 0; return gspca_dev->sd_desc->get_register(gspca_dev, reg); } @@ -1064,12 +1059,6 @@ static int vidioc_s_register(struct file *file, void *priv, { struct gspca_dev *gspca_dev = video_drvdata(file); - if (!gspca_dev->sd_desc->get_chip_ident) - return -ENOTTY; - - if (!gspca_dev->sd_desc->set_register) - return -ENOTTY; - gspca_dev->usb_err = 0; return gspca_dev->sd_desc->set_register(gspca_dev, reg); } @@ -1080,9 +1069,6 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, { struct gspca_dev *gspca_dev = video_drvdata(file); - if (!gspca_dev->sd_desc->get_chip_ident) - return -ENOTTY; - gspca_dev->usb_err = 0; return gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); } @@ -1136,8 +1122,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, int mode; mode = gspca_dev->curr_mode; - memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], - sizeof fmt->fmt.pix); + fmt->fmt.pix = gspca_dev->cam.cam_mode[mode]; + /* some drivers use priv internally, zero it before giving it to + userspace */ + fmt->fmt.pix.priv = 0; return 0; } @@ -1168,8 +1156,10 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, /* else ; * no chance, return this mode */ } - memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], - sizeof fmt->fmt.pix); + fmt->fmt.pix = gspca_dev->cam.cam_mode[mode]; + /* some drivers use priv internally, zero it before giving it to + userspace */ + fmt->fmt.pix.priv = 0; return mode; /* used when s_fmt */ } @@ -1284,9 +1274,6 @@ static void gspca_release(struct v4l2_device *v4l2_device) struct gspca_dev *gspca_dev = container_of(v4l2_device, struct gspca_dev, v4l2_dev); - PDEBUG(D_PROBE, "%s released", - video_device_node_name(&gspca_dev->vdev)); - v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler); v4l2_device_unregister(&gspca_dev->v4l2_dev); kfree(gspca_dev->usb_buf); @@ -1694,8 +1681,6 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv, { struct gspca_dev *gspca_dev = video_drvdata(file); - if (!gspca_dev->sd_desc->get_jcomp) - return -ENOTTY; gspca_dev->usb_err = 0; return gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); } @@ -1705,8 +1690,6 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, { struct gspca_dev *gspca_dev = video_drvdata(file); - if (!gspca_dev->sd_desc->set_jcomp) - return -ENOTTY; gspca_dev->usb_err = 0; return gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); } @@ -2290,6 +2273,20 @@ int gspca_dev_probe2(struct usb_interface *intf, v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_DQBUF); v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QBUF); v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QUERYBUF); + if (!gspca_dev->sd_desc->get_chip_ident) + v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_G_CHIP_IDENT); +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (!gspca_dev->sd_desc->get_chip_ident || + !gspca_dev->sd_desc->get_register) + v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_G_REGISTER); + if (!gspca_dev->sd_desc->get_chip_ident || + !gspca_dev->sd_desc->set_register) + v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_DBG_S_REGISTER); +#endif + if (!gspca_dev->sd_desc->get_jcomp) + v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_G_JPEGCOMP); + if (!gspca_dev->sd_desc->set_jcomp) + v4l2_disable_ioctl(&gspca_dev->vdev, VIDIOC_S_JPEGCOMP); /* init video stuff */ ret = video_register_device(&gspca_dev->vdev, @@ -2429,7 +2426,6 @@ int gspca_resume(struct usb_interface *intf) */ streaming = gspca_dev->streaming; gspca_dev->streaming = 0; - v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler); if (streaming) ret = gspca_init_transfer(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 5ab3f7e12760..26b99310d628 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c @@ -54,21 +54,13 @@ enum { #define CAMQUALITY_MIN 0 /* highest cam quality */ #define CAMQUALITY_MAX 97 /* lowest cam quality */ -enum e_ctrl { - LIGHTFREQ, - AUTOGAIN, - RED, - GREEN, - BLUE, - NCTRLS /* number of controls */ -}; - /* Structure to hold all of our device specific stuff */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; int blocks_left; const struct v4l2_pix_format *cap_mode; + struct v4l2_ctrl *freq; + struct v4l2_ctrl *jpegqual; /* Driver stuff */ u8 type; u8 quality; /* image quality */ @@ -139,23 +131,21 @@ static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) } } -static void setfreq(struct gspca_dev *gspca_dev) +static void setfreq(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 freq_commands[][2] = { {0x71, 0x80}, {0x70, 0x07} }; - freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1); + freq_commands[0][1] |= val >> 1; jlj_write2(gspca_dev, freq_commands[0]); jlj_write2(gspca_dev, freq_commands[1]); } -static void setcamquality(struct gspca_dev *gspca_dev) +static void setcamquality(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 quality_commands[][2] = { {0x71, 0x1E}, {0x70, 0x06} @@ -163,7 +153,7 @@ static void setcamquality(struct gspca_dev *gspca_dev) u8 camquality; /* adapt camera quality from jpeg quality */ - camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX) + camquality = ((QUALITY_MAX - val) * CAMQUALITY_MAX) / (QUALITY_MAX - QUALITY_MIN); quality_commands[0][1] += camquality; @@ -171,130 +161,58 @@ static void setcamquality(struct gspca_dev *gspca_dev) jlj_write2(gspca_dev, quality_commands[1]); } -static void setautogain(struct gspca_dev *gspca_dev) +static void setautogain(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 autogain_commands[][2] = { {0x94, 0x02}, {0xcf, 0x00} }; - autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4); + autogain_commands[1][1] = val << 4; jlj_write2(gspca_dev, autogain_commands[0]); jlj_write2(gspca_dev, autogain_commands[1]); } -static void setred(struct gspca_dev *gspca_dev) +static void setred(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 setred_commands[][2] = { {0x94, 0x02}, {0xe6, 0x00} }; - setred_commands[1][1] = sd->ctrls[RED].val; + setred_commands[1][1] = val; jlj_write2(gspca_dev, setred_commands[0]); jlj_write2(gspca_dev, setred_commands[1]); } -static void setgreen(struct gspca_dev *gspca_dev) +static void setgreen(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 setgreen_commands[][2] = { {0x94, 0x02}, {0xe7, 0x00} }; - setgreen_commands[1][1] = sd->ctrls[GREEN].val; + setgreen_commands[1][1] = val; jlj_write2(gspca_dev, setgreen_commands[0]); jlj_write2(gspca_dev, setgreen_commands[1]); } -static void setblue(struct gspca_dev *gspca_dev) +static void setblue(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 setblue_commands[][2] = { {0x94, 0x02}, {0xe9, 0x00} }; - setblue_commands[1][1] = sd->ctrls[BLUE].val; + setblue_commands[1][1] = val; jlj_write2(gspca_dev, setblue_commands[0]); jlj_write2(gspca_dev, setblue_commands[1]); } -static const struct ctrl sd_ctrls[NCTRLS] = { -[LIGHTFREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */ - .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */ - .step = 1, - .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, - }, - .set_control = setfreq - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Automatic Gain (and Exposure)", - .minimum = 0, - .maximum = 3, - .step = 1, -#define AUTOGAIN_DEF 0 - .default_value = AUTOGAIN_DEF, - }, - .set_control = setautogain - }, -[RED] = { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0, - .maximum = 3, - .step = 1, -#define RED_BALANCE_DEF 2 - .default_value = RED_BALANCE_DEF, - }, - .set_control = setred - }, - -[GREEN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0, - .maximum = 3, - .step = 1, -#define GREEN_BALANCE_DEF 2 - .default_value = GREEN_BALANCE_DEF, - }, - .set_control = setgreen - }, -[BLUE] = { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0, - .maximum = 3, - .step = 1, -#define BLUE_BALANCE_DEF 2 - .default_value = BLUE_BALANCE_DEF, - }, - .set_control = setblue - }, -}; - static int jlj_start(struct gspca_dev *gspca_dev) { int i; @@ -344,9 +262,9 @@ static int jlj_start(struct gspca_dev *gspca_dev) if (start_commands[i].ack_wanted) jlj_read1(gspca_dev, response); } - setcamquality(gspca_dev); + setcamquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual)); msleep(2); - setfreq(gspca_dev); + setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq)); if (gspca_dev->usb_err < 0) PDEBUG(D_ERR, "Start streaming command failed"); return gspca_dev->usb_err; @@ -403,7 +321,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *dev = (struct sd *) gspca_dev; dev->type = id->driver_info; - gspca_dev->cam.ctrls = dev->ctrls; dev->quality = QUALITY_DEF; cam->cam_mode = jlj_mode; @@ -479,25 +396,81 @@ static const struct usb_device_id device_table[] = { MODULE_DEVICE_TABLE(usb, device_table); -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - switch (menu->id) { + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "disable"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } + setfreq(gspca_dev, ctrl->val); + break; + case V4L2_CID_RED_BALANCE: + setred(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + setgreen(gspca_dev, ctrl->val); + break; + case V4L2_CID_BLUE_BALANCE: + setblue(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + setautogain(gspca_dev, ctrl->val); + break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + jpeg_set_qual(sd->jpeg_hdr, ctrl->val); + setcamquality(gspca_dev, ctrl->val); break; } - return -EINVAL; + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + static const struct v4l2_ctrl_config custom_autogain = { + .ops = &sd_ctrl_ops, + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Automatic Gain (and Exposure)", + .max = 3, + .step = 1, + .def = 0, + }; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 6); + sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ); + v4l2_ctrl_new_custom(hdl, &custom_autogain, NULL); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 3, 1, 2); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 3, 1, 2); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 3, 1, 2); + sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, + QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + return 0; } static int sd_set_jcomp(struct gspca_dev *gspca_dev, @@ -505,16 +478,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) { - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - setcamquality(gspca_dev); - } + v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality); return 0; } @@ -524,7 +488,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; + jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT; return 0; @@ -546,12 +510,10 @@ static const struct sd_desc sd_desc_sportscam_dv15 = { .name = MODULE_NAME, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), - .querymenu = sd_querymenu, .get_jcomp = sd_get_jcomp, .set_jcomp = sd_set_jcomp, }; @@ -579,6 +541,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c index 9c591c7c6f54..cf9d9fca5b84 100644 --- a/drivers/media/video/gspca/jl2005bcd.c +++ b/drivers/media/video/gspca/jl2005bcd.c @@ -505,8 +505,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - /* .ctrls = none have been detected */ - /* .nctrls = ARRAY_SIZE(sd_ctrls), */ .config = sd_config, .init = sd_init, .start = sd_start, @@ -536,6 +534,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c index e8e8f2fe9166..40ad6687ee5d 100644 --- a/drivers/media/video/gspca/kinect.c +++ b/drivers/media/video/gspca/kinect.c @@ -63,12 +63,6 @@ struct sd { uint8_t ibuf[0x200]; /* input buffer for control commands */ }; -/* V4L2 controls supported by the driver */ -/* controls prototypes here */ - -static const struct ctrl sd_ctrls[] = { -}; - #define MODE_640x480 0x0001 #define MODE_640x488 0x0002 #define MODE_1280x1024 0x0004 @@ -373,15 +367,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, /* - .querymenu = sd_querymenu, .get_streamparm = sd_get_streamparm, .set_streamparm = sd_set_streamparm, */ @@ -410,6 +401,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c index f0c0d74dfe92..bbf91e07e38b 100644 --- a/drivers/media/video/gspca/konica.c +++ b/drivers/media/video/gspca/konica.c @@ -50,107 +50,8 @@ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ struct urb *last_data_urb; u8 snapshot_pressed; - u8 brightness; - u8 contrast; - u8 saturation; - u8 whitebal; - u8 sharpness; }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 9, - .step = 1, -#define BRIGHTNESS_DEFAULT 4 - .default_value = BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 9, - .step = 4, -#define CONTRAST_DEFAULT 10 - .default_value = CONTRAST_DEFAULT, - .flags = 0, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SD_SATURATION 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 9, - .step = 1, -#define SATURATION_DEFAULT 4 - .default_value = SATURATION_DEFAULT, - .flags = 0, - }, - .set = sd_setsaturation, - .get = sd_getsaturation, - }, -#define SD_WHITEBAL 3 - { - { - .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "White Balance", - .minimum = 0, - .maximum = 33, - .step = 1, -#define WHITEBAL_DEFAULT 25 - .default_value = WHITEBAL_DEFAULT, - .flags = 0, - }, - .set = sd_setwhitebal, - .get = sd_getwhitebal, - }, -#define SD_SHARPNESS 4 - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 9, - .step = 1, -#define SHARPNESS_DEFAULT 4 - .default_value = SHARPNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, -}; /* .priv is what goes to register 8 for this mode, known working values: 0x00 -> 176x144, cropped @@ -202,7 +103,8 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) 0, 1000); if (ret < 0) { - pr_err("reg_w err %d\n", ret); + pr_err("reg_w err writing %02x to %02x: %d\n", + value, index, ret); gspca_dev->usb_err = ret; } } @@ -223,7 +125,7 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index) 2, 1000); if (ret < 0) { - pr_err("reg_w err %d\n", ret); + pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; } } @@ -242,34 +144,33 @@ static void konica_stream_off(struct gspca_dev *gspca_dev) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; - gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); gspca_dev->cam.no_urb_create = 1; - sd->brightness = BRIGHTNESS_DEFAULT; - sd->contrast = CONTRAST_DEFAULT; - sd->saturation = SATURATION_DEFAULT; - sd->whitebal = WHITEBAL_DEFAULT; - sd->sharpness = SHARPNESS_DEFAULT; - return 0; } /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { - /* HDG not sure if these 2 reads are needed */ - reg_r(gspca_dev, 0, 0x10); - PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); - reg_r(gspca_dev, 0, 0x10); - PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x", - gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); + int i; + + /* + * The konica needs a freaking large time to "boot" (approx 6.5 sec.), + * and does not want to be bothered while doing so :| + * Register 0x10 counts from 1 - 3, with 3 being "ready" + */ + msleep(6000); + for (i = 0; i < 20; i++) { + reg_r(gspca_dev, 0, 0x10); + if (gspca_dev->usb_buf[0] == 3) + break; + msleep(100); + } reg_w(gspca_dev, 0, 0x0d); - return 0; + return gspca_dev->usb_err; } static int sd_start(struct gspca_dev *gspca_dev) @@ -289,12 +190,6 @@ static int sd_start(struct gspca_dev *gspca_dev) packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); - reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG); - reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG); - reg_w(gspca_dev, sd->contrast, CONTRAST_REG); - reg_w(gspca_dev, sd->saturation, SATURATION_REG); - reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG); - n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; reg_w(gspca_dev, n, 0x08); @@ -479,125 +374,82 @@ resubmit: pr_err("usb_submit_urb(status_urb) ret %d\n", st); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) { - konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG); - konica_stream_on(gspca_dev); - } - - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - return 0; -} + gspca_dev->usb_err = 0; -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - sd->contrast = val; - if (gspca_dev->streaming) { + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->contrast, CONTRAST_REG); + reg_w(gspca_dev, ctrl->val, BRIGHTNESS_REG); konica_stream_on(gspca_dev); - } - - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - - return 0; -} - -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->saturation = val; - if (gspca_dev->streaming) { + break; + case V4L2_CID_CONTRAST: konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->saturation, SATURATION_REG); + reg_w(gspca_dev, ctrl->val, CONTRAST_REG); konica_stream_on(gspca_dev); - } - return 0; -} - -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->saturation; - - return 0; -} - -static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->whitebal = val; - if (gspca_dev->streaming) { + break; + case V4L2_CID_SATURATION: konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG); + reg_w(gspca_dev, ctrl->val, SATURATION_REG); konica_stream_on(gspca_dev); - } - return 0; -} - -static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->whitebal; - - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) { + break; + case V4L2_CID_WHITE_BALANCE_TEMPERATURE: konica_stream_off(gspca_dev); - reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG); + reg_w(gspca_dev, ctrl->val, WHITEBAL_REG); konica_stream_on(gspca_dev); + break; + case V4L2_CID_SHARPNESS: + konica_stream_off(gspca_dev); + reg_w(gspca_dev, ctrl->val, SHARPNESS_REG); + konica_stream_on(gspca_dev); + break; } - return 0; + return gspca_dev->usb_err; } -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 5); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 9, 1, 4); + /* Needs to be verified */ + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 9, 1, 4); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 9, 1, 4); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_WHITE_BALANCE_TEMPERATURE, + 0, 33, 1, 25); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 9, 1, 4); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) @@ -628,6 +480,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index 0c4493675438..ed22638978ce 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -400,6 +400,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif .disconnect = m5602_disconnect }; diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index ec7b21ee79fb..ff2c5abf115b 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -30,6 +30,8 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); MODULE_LICENSE("GPL"); +#define QUALITY 50 + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ @@ -42,13 +44,6 @@ struct sd { struct v4l2_ctrl *illum_top; struct v4l2_ctrl *illum_bottom; }; - struct v4l2_ctrl *jpegqual; - - u8 quality; -#define QUALITY_MIN 40 -#define QUALITY_MAX 70 -#define QUALITY_DEF 50 - u8 jpeg_hdr[JPEG_HDR_SZ]; }; @@ -194,9 +189,6 @@ static int mars_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_SHARPNESS: setsharpness(gspca_dev, ctrl->val); break; - case V4L2_CID_JPEG_COMPRESSION_QUALITY: - jpeg_set_qual(sd->jpeg_hdr, ctrl->val); - break; default: return -EINVAL; } @@ -214,7 +206,7 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; gspca_dev->vdev.ctrl_handler = hdl; - v4l2_ctrl_handler_init(hdl, 7); + v4l2_ctrl_handler_init(hdl, 6); sd->brightness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 30, 1, 15); sd->saturation = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, @@ -229,9 +221,6 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) sd->illum_bottom = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0); sd->illum_bottom->flags |= V4L2_CTRL_FLAG_UPDATE; - sd->jpegqual = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, - V4L2_CID_JPEG_COMPRESSION_QUALITY, - QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF); if (hdl->error) { pr_err("Could not initialize controls\n"); return hdl->error; @@ -244,13 +233,11 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; cam = &gspca_dev->cam; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - sd->quality = QUALITY_DEF; return 0; } @@ -269,7 +256,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ - jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual)); + jpeg_set_qual(sd->jpeg_hdr, QUALITY); data = gspca_dev->usb_buf; @@ -411,31 +398,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - int ret; - - ret = v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality); - if (ret) - return ret; - jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); - return 0; -} - -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; - return 0; -} - /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, @@ -445,8 +407,6 @@ static const struct sd_desc sd_desc = { .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, }; /* -- module initialisation -- */ diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c index d73e5bd3dbf7..8f4714df5990 100644 --- a/drivers/media/video/gspca/mr97310a.c +++ b/drivers/media/video/gspca/mr97310a.c @@ -67,6 +67,7 @@ #define MR97310A_CS_GAIN_MAX 0x7ff #define MR97310A_CS_GAIN_DEFAULT 0x110 +#define MR97310A_CID_CLOCKDIV (V4L2_CTRL_CLASS_USER + 0x1000) #define MR97310A_MIN_CLOCKDIV_MIN 3 #define MR97310A_MIN_CLOCKDIV_MAX 8 #define MR97310A_MIN_CLOCKDIV_DEFAULT 3 @@ -84,17 +85,15 @@ MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + struct { /* exposure/min_clockdiv control cluster */ + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *min_clockdiv; + }; u8 sof_read; u8 cam_type; /* 0 is CIF and 1 is VGA */ u8 sensor_type; /* We use 0 and 1 here, too. */ u8 do_lcd_stop; u8 adj_colors; - - int brightness; - u16 exposure; - u32 gain; - u8 contrast; - u8 min_clockdiv; }; struct sensor_w_data { @@ -105,132 +104,6 @@ struct sensor_w_data { }; static void sd_stopN(struct gspca_dev *gspca_dev); -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val); -static void setbrightness(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static void setgain(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); - -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[] = { -/* Separate brightness control description for Argus QuickClix as it has - * different limits from the other mr97310a cameras, and separate gain - * control for Sakar CyberPix camera. */ - { -#define NORM_BRIGHTNESS_IDX 0 - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = -254, - .maximum = 255, - .step = 1, - .default_value = MR97310A_BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { -#define ARGUS_QC_BRIGHTNESS_IDX 1 - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = MR97310A_BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { -#define EXPOSURE_IDX 2 - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = MR97310A_EXPOSURE_MIN, - .maximum = MR97310A_EXPOSURE_MAX, - .step = 1, - .default_value = MR97310A_EXPOSURE_DEFAULT, - .flags = 0, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { -#define GAIN_IDX 3 - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = MR97310A_GAIN_MIN, - .maximum = MR97310A_GAIN_MAX, - .step = 1, - .default_value = MR97310A_GAIN_DEFAULT, - .flags = 0, - }, - .set = sd_setgain, - .get = sd_getgain, - }, - { -#define SAKAR_CS_GAIN_IDX 4 - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = MR97310A_CS_GAIN_MIN, - .maximum = MR97310A_CS_GAIN_MAX, - .step = 1, - .default_value = MR97310A_CS_GAIN_DEFAULT, - .flags = 0, - }, - .set = sd_setgain, - .get = sd_getgain, - }, - { -#define CONTRAST_IDX 5 - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = MR97310A_CONTRAST_MIN, - .maximum = MR97310A_CONTRAST_MAX, - .step = 1, - .default_value = MR97310A_CONTRAST_DEFAULT, - .flags = 0, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { -#define MIN_CLOCKDIV_IDX 6 - { - .id = V4L2_CID_PRIVATE_BASE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Minimum Clock Divider", - .minimum = MR97310A_MIN_CLOCKDIV_MIN, - .maximum = MR97310A_MIN_CLOCKDIV_MAX, - .step = 1, - .default_value = MR97310A_MIN_CLOCKDIV_DEFAULT, - .flags = 0, - }, - .set = sd_setmin_clockdiv, - .get = sd_getmin_clockdiv, - }, -}; static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, @@ -481,7 +354,6 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - int gain_default = MR97310A_GAIN_DEFAULT; int err_code; cam = &gspca_dev->cam; @@ -615,52 +487,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor_type); } - /* Setup controls depending on camera type */ - if (sd->cam_type == CAM_TYPE_CIF) { - /* No brightness for sensor_type 0 */ - if (sd->sensor_type == 0) - gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | - (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX); - else - gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX) | - (1 << MIN_CLOCKDIV_IDX); - } else { - /* All controls need to be disabled if VGA sensor_type is 0 */ - if (sd->sensor_type == 0) - gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | - (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << EXPOSURE_IDX) | - (1 << GAIN_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX) | - (1 << MIN_CLOCKDIV_IDX); - else if (sd->sensor_type == 2) { - gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | - (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << GAIN_IDX) | - (1 << MIN_CLOCKDIV_IDX); - gain_default = MR97310A_CS_GAIN_DEFAULT; - } else if (sd->do_lcd_stop) - /* Argus QuickClix has different brightness limits */ - gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX); - else - gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) | - (1 << CONTRAST_IDX) | - (1 << SAKAR_CS_GAIN_IDX); - } - - sd->brightness = MR97310A_BRIGHTNESS_DEFAULT; - sd->exposure = MR97310A_EXPOSURE_DEFAULT; - sd->gain = gain_default; - sd->contrast = MR97310A_CONTRAST_DEFAULT; - sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT; - return 0; } @@ -952,11 +778,6 @@ static int sd_start(struct gspca_dev *gspca_dev) if (err_code < 0) return err_code; - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setexposure(gspca_dev); - setgain(gspca_dev); - return isoc_enable(gspca_dev); } @@ -971,37 +792,25 @@ static void sd_stopN(struct gspca_dev *gspca_dev) lcd_stop(gspca_dev); } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - u8 val; u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */ u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */ static const u8 quick_clix_table[] = /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ { 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15}; - /* - * This control is disabled for CIF type 1 and VGA type 0 cameras. - * It does not quite act linearly for the Argus QuickClix camera, - * but it does control brightness. The values are 0 - 15 only, and - * the table above makes them act consecutively. - */ - if ((gspca_dev->ctrl_dis & (1 << NORM_BRIGHTNESS_IDX)) && - (gspca_dev->ctrl_dis & (1 << ARGUS_QC_BRIGHTNESS_IDX))) - return; - if (sd->cam_type == CAM_TYPE_VGA) { sign_reg += 4; value_reg += 4; } /* Note register 7 is also seen as 0x8x or 0xCx in some dumps */ - if (sd->brightness > 0) { + if (val > 0) { sensor_write1(gspca_dev, sign_reg, 0x00); - val = sd->brightness; } else { sensor_write1(gspca_dev, sign_reg, 0x01); - val = (257 - sd->brightness); + val = 257 - val; } /* Use lookup table for funky Argus QuickClix brightness */ if (sd->do_lcd_stop) @@ -1010,23 +819,20 @@ static void setbrightness(struct gspca_dev *gspca_dev) sensor_write1(gspca_dev, value_reg, val); } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 min_clockdiv) { struct sd *sd = (struct sd *) gspca_dev; int exposure = MR97310A_EXPOSURE_DEFAULT; u8 buf[2]; - if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) - return; - if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) { /* This cam does not like exposure settings < 300, so scale 0 - 4095 to 300 - 4095 */ - exposure = (sd->exposure * 9267) / 10000 + 300; + exposure = (expo * 9267) / 10000 + 300; sensor_write1(gspca_dev, 3, exposure >> 4); sensor_write1(gspca_dev, 4, exposure & 0x0f); } else if (sd->sensor_type == 2) { - exposure = sd->exposure; + exposure = expo; exposure >>= 3; sensor_write1(gspca_dev, 3, exposure >> 8); sensor_write1(gspca_dev, 4, exposure & 0xff); @@ -1038,11 +844,11 @@ static void setexposure(struct gspca_dev *gspca_dev) Note our 0 - 4095 exposure is mapped to 0 - 511 milliseconds exposure time */ - u8 clockdiv = (60 * sd->exposure + 7999) / 8000; + u8 clockdiv = (60 * expo + 7999) / 8000; /* Limit framerate to not exceed usb bandwidth */ - if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320) - clockdiv = sd->min_clockdiv; + if (clockdiv < min_clockdiv && gspca_dev->width >= 320) + clockdiv = min_clockdiv; else if (clockdiv < 2) clockdiv = 2; @@ -1051,7 +857,7 @@ static void setexposure(struct gspca_dev *gspca_dev) /* Frame exposure time in ms = 1000 * clockdiv / 60 -> exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */ - exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv); + exposure = (60 * 511 * expo) / (8000 * clockdiv); if (exposure > 511) exposure = 511; @@ -1065,125 +871,148 @@ static void setexposure(struct gspca_dev *gspca_dev) } } -static void setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; u8 gainreg; - if ((gspca_dev->ctrl_dis & (1 << GAIN_IDX)) && - (gspca_dev->ctrl_dis & (1 << SAKAR_CS_GAIN_IDX))) - return; - if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) - sensor_write1(gspca_dev, 0x0e, sd->gain); + sensor_write1(gspca_dev, 0x0e, val); else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2) for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) { - sensor_write1(gspca_dev, gainreg, sd->gain >> 8); - sensor_write1(gspca_dev, gainreg + 1, sd->gain & 0xff); + sensor_write1(gspca_dev, gainreg, val >> 8); + sensor_write1(gspca_dev, gainreg + 1, val & 0xff); } else - sensor_write1(gspca_dev, 0x10, sd->gain); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX)) - return; - - sensor_write1(gspca_dev, 0x1c, sd->contrast); -} - - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; + sensor_write1(gspca_dev, 0x10, val); } -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; + sensor_write1(gspca_dev, 0x1c, val); } -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} + gspca_dev->usb_err = 0; -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} + if (!gspca_dev->streaming) + return 0; -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + setexposure(gspca_dev, sd->exposure->val, + sd->min_clockdiv ? sd->min_clockdiv->val : 0); + break; + case V4L2_CID_GAIN: + setgain(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + static const struct v4l2_ctrl_config clockdiv = { + .ops = &sd_ctrl_ops, + .id = MR97310A_CID_CLOCKDIV, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Minimum Clock Divider", + .min = MR97310A_MIN_CLOCKDIV_MIN, + .max = MR97310A_MIN_CLOCKDIV_MAX, + .step = 1, + .def = MR97310A_MIN_CLOCKDIV_DEFAULT, + }; + bool has_brightness = false; + bool has_argus_brightness = false; + bool has_contrast = false; + bool has_gain = false; + bool has_cs_gain = false; + bool has_exposure = false; + bool has_clockdiv = false; - sd->min_clockdiv = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); -static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + /* Setup controls depending on camera type */ + if (sd->cam_type == CAM_TYPE_CIF) { + /* No brightness for sensor_type 0 */ + if (sd->sensor_type == 0) + has_exposure = has_gain = has_clockdiv = true; + else + has_exposure = has_gain = has_brightness = true; + } else { + /* All controls need to be disabled if VGA sensor_type is 0 */ + if (sd->sensor_type == 0) + ; /* no controls! */ + else if (sd->sensor_type == 2) + has_exposure = has_cs_gain = has_contrast = true; + else if (sd->do_lcd_stop) + has_exposure = has_gain = has_argus_brightness = + has_clockdiv = true; + else + has_exposure = has_gain = has_brightness = + has_clockdiv = true; + } - *val = sd->min_clockdiv; + /* Separate brightness control description for Argus QuickClix as it has + * different limits from the other mr97310a cameras, and separate gain + * control for Sakar CyberPix camera. */ + /* + * This control is disabled for CIF type 1 and VGA type 0 cameras. + * It does not quite act linearly for the Argus QuickClix camera, + * but it does control brightness. The values are 0 - 15 only, and + * the table above makes them act consecutively. + */ + if (has_brightness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, -254, 255, 1, + MR97310A_BRIGHTNESS_DEFAULT); + else if (has_argus_brightness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 15, 1, + MR97310A_BRIGHTNESS_DEFAULT); + if (has_contrast) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, MR97310A_CONTRAST_MIN, + MR97310A_CONTRAST_MAX, 1, MR97310A_CONTRAST_DEFAULT); + if (has_gain) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, MR97310A_GAIN_MIN, MR97310A_GAIN_MAX, + 1, MR97310A_GAIN_DEFAULT); + else if (has_cs_gain) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAIN, + MR97310A_CS_GAIN_MIN, MR97310A_CS_GAIN_MAX, + 1, MR97310A_CS_GAIN_DEFAULT); + if (has_exposure) + sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, MR97310A_EXPOSURE_MIN, + MR97310A_EXPOSURE_MAX, 1, MR97310A_EXPOSURE_DEFAULT); + if (has_clockdiv) + sd->min_clockdiv = v4l2_ctrl_new_custom(hdl, &clockdiv, NULL); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + if (has_exposure && has_clockdiv) + v4l2_ctrl_cluster(2, &sd->exposure); return 0; } @@ -1221,10 +1050,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, @@ -1256,6 +1084,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index 42e021931e60..44c9964b1b3e 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -32,22 +32,10 @@ MODULE_LICENSE("GPL"); static int webcam; -/* controls */ -enum e_ctrl { - GAIN, - EXPOSURE, - AUTOGAIN, - NCTRLS /* number of controls */ -}; - -#define AUTOGAIN_DEF 1 - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; - u32 ae_res; s8 ag_cnt; #define AG_CNT_START 13 @@ -1667,17 +1655,13 @@ static int swap_bits(int v) return r; } -static void setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev, u8 val) { struct sd *sd = (struct sd *) gspca_dev; - u8 val, v[2]; + u8 v[2]; - val = sd->ctrls[GAIN].val; switch (sd->webcam) { case P35u: - /* Note the control goes from 0-255 not 0-127, but anything - above 127 just means amplifying noise */ - val >>= 1; /* 0 - 255 -> 0 - 127 */ reg_w(gspca_dev, 0x1026, &val, 1); break; case Kr651us: @@ -1690,13 +1674,11 @@ static void setgain(struct gspca_dev *gspca_dev) } } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s16 val; u8 v[2]; - val = sd->ctrls[EXPOSURE].val; switch (sd->webcam) { case P35u: v[0] = ((9 - val) << 3) | 0x01; @@ -1713,14 +1695,12 @@ static void setexposure(struct gspca_dev *gspca_dev) } } -static void setautogain(struct gspca_dev *gspca_dev) +static void setautogain(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; int w, h; - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) - return; - if (!sd->ctrls[AUTOGAIN].val) { + if (!val) { sd->ag_cnt = -1; return; } @@ -1763,7 +1743,6 @@ static int sd_config(struct gspca_dev *gspca_dev, if ((unsigned) webcam >= NWEBCAMS) webcam = 0; sd->webcam = webcam; - gspca_dev->cam.ctrls = sd->ctrls; gspca_dev->cam.needs_full_bandwidth = 1; sd->ag_cnt = -1; @@ -1834,33 +1813,7 @@ static int sd_config(struct gspca_dev *gspca_dev, break; } } - switch (sd->webcam) { - case P35u: -/* sd->ctrls[EXPOSURE].max = 9; - * sd->ctrls[EXPOSURE].def = 9; */ - /* coarse expo auto gain function gain minimum, to avoid - * a large settings jump the first auto adjustment */ - sd->ctrls[GAIN].def = 255 / 5 * 2; - break; - case Cvideopro: - case DvcV6: - case Kritter: - gspca_dev->ctrl_dis = (1 << GAIN) | (1 << AUTOGAIN); - /* fall thru */ - case Kr651us: - sd->ctrls[EXPOSURE].max = 315; - sd->ctrls[EXPOSURE].def = 150; - break; - default: - gspca_dev->ctrl_dis = (1 << GAIN) | (1 << EXPOSURE) - | (1 << AUTOGAIN); - break; - } -#if AUTOGAIN_DEF - if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN))) - gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); -#endif return gspca_dev->usb_err; } @@ -1925,9 +1878,6 @@ static int sd_start(struct gspca_dev *gspca_dev) break; } - setgain(gspca_dev); - setexposure(gspca_dev); - setautogain(gspca_dev); sd->exp_too_high_cnt = 0; sd->exp_too_low_cnt = 0; return gspca_dev->usb_err; @@ -1987,24 +1937,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AUTOGAIN].val = val; - if (val) - gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); - else - gspca_dev->ctrl_inac = 0; - if (gspca_dev->streaming) - setautogain(gspca_dev); - return gspca_dev->usb_err; -} - -#define WANT_REGULAR_AUTOGAIN -#define WANT_COARSE_EXPO_AUTOGAIN -#include "autogain_functions.h" - static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -2024,62 +1956,100 @@ static void do_autogain(struct gspca_dev *gspca_dev) switch (sd->webcam) { case P35u: - coarse_grained_expo_autogain(gspca_dev, luma, 100, 5); + gspca_coarse_grained_expo_autogain(gspca_dev, luma, 100, 5); break; default: - auto_gain_n_exposure(gspca_dev, luma, 100, 5, 230, 0); + gspca_expo_autogain(gspca_dev, luma, 100, 5, 230, 0); break; } } -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[NCTRLS] = { -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 253, - .step = 1, - .default_value = 128 - }, - .set_control = setgain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 9, - .step = 1, - .default_value = 9 - }, - .set_control = setexposure - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = AUTOGAIN_DEF, - .flags = V4L2_CTRL_FLAG_UPDATE - }, - .set = sd_setautogain - }, + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + /* autogain/gain/exposure control cluster */ + case V4L2_CID_AUTOGAIN: + if (ctrl->is_new) + setautogain(gspca_dev, ctrl->val); + if (!ctrl->val) { + if (gspca_dev->gain->is_new) + setgain(gspca_dev, gspca_dev->gain->val); + if (gspca_dev->exposure->is_new) + setexposure(gspca_dev, + gspca_dev->exposure->val); + } + break; + /* Some webcams only have exposure, so handle that separately from the + autogain/gain/exposure cluster in the previous case. */ + case V4L2_CID_EXPOSURE: + setexposure(gspca_dev, gspca_dev->exposure->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, }; +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 3); + switch (sd->webcam) { + case P35u: + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + /* For P35u choose coarse expo auto gain function gain minimum, + * to avoid a large settings jump the first auto adjustment */ + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 127 / 5 * 2); + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 9, 1, 9); + break; + case Kr651us: + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 253, 1, 128); + /* fall through */ + case Cvideopro: + case DvcV6: + case Kritter: + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 315, 1, 150); + break; + default: + break; + } + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + if (gspca_dev->autogain) + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, @@ -2117,6 +2087,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 183457c5cfdb..bfc7cefa59f8 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -60,25 +60,20 @@ static int frame_rate; * are getting "Failed to read sensor ID..." */ static int i2c_detect_tries = 10; -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - EXPOSURE, - COLORS, - HFLIP, - VFLIP, - AUTOBRIGHT, - AUTOGAIN, - FREQ, - NCTRL /* number of controls */ -}; - /* ov519 device descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRL]; + struct v4l2_ctrl *jpegqual; + struct v4l2_ctrl *freq; + struct { /* h/vflip control cluster */ + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + }; + struct { /* autobrightness/brightness control cluster */ + struct v4l2_ctrl *autobright; + struct v4l2_ctrl *brightness; + }; u8 packet_nr; @@ -101,7 +96,6 @@ struct sd { /* Determined by sensor type */ u8 sif; - u8 quality; #define QUALITY_MIN 50 #define QUALITY_MAX 70 #define QUALITY_DEF 50 @@ -145,209 +139,112 @@ enum sensors { really should move the sensor drivers to v4l2 sub drivers. */ #include "w996Xcf.c" -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void sethvflip(struct gspca_dev *gspca_dev); -static void setautobright(struct gspca_dev *gspca_dev); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static void setfreq(struct gspca_dev *gspca_dev); -static void setfreq_i(struct sd *sd); - -static const struct ctrl sd_ctrls[] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setbrightness, +/* table of the disabled controls */ +struct ctrl_valid { + int has_brightness:1; + int has_contrast:1; + int has_exposure:1; + int has_autogain:1; + int has_sat:1; + int has_hvflip:1; + int has_autobright:1; + int has_freq:1; +}; + +static const struct ctrl_valid valid_controls[] = { + [SEN_OV2610] = { + .has_exposure = 1, + .has_autogain = 1, }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setcontrast, + [SEN_OV2610AE] = { + .has_exposure = 1, + .has_autogain = 1, }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setexposure, + [SEN_OV3610] = { + /* No controls */ }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setcolors, + [SEN_OV6620] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_autobright = 1, + .has_freq = 1, }, -/* The flip controls work for sensors ov7660 and ov7670 only */ -[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip, + [SEN_OV6630] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_autobright = 1, + .has_freq = 1, }, -[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip, + [SEN_OV66308AF] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_autobright = 1, + .has_freq = 1, }, -[AUTOBRIGHT] = { - { - .id = V4L2_CID_AUTOBRIGHTNESS, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Brightness", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set_control = setautobright, + [SEN_OV7610] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_autobright = 1, + .has_freq = 1, }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .flags = V4L2_CTRL_FLAG_UPDATE - }, - .set = sd_setautogain, + [SEN_OV7620] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_autobright = 1, + .has_freq = 1, }, -[FREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: no flicker, 1: 50Hz, 2:60Hz, 3: auto */ - .step = 1, - .default_value = 0, - }, - .set_control = setfreq, + [SEN_OV7620AE] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_autobright = 1, + .has_freq = 1, + }, + [SEN_OV7640] = { + .has_brightness = 1, + .has_sat = 1, + .has_freq = 1, + }, + [SEN_OV7648] = { + .has_brightness = 1, + .has_sat = 1, + .has_freq = 1, + }, + [SEN_OV7660] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_hvflip = 1, + .has_freq = 1, + }, + [SEN_OV7670] = { + .has_brightness = 1, + .has_contrast = 1, + .has_hvflip = 1, + .has_freq = 1, + }, + [SEN_OV76BE] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_autobright = 1, + .has_freq = 1, + }, + [SEN_OV8610] = { + .has_brightness = 1, + .has_contrast = 1, + .has_sat = 1, + .has_autobright = 1, + }, + [SEN_OV9600] = { + .has_exposure = 1, + .has_autogain = 1, }, -}; - -/* table of the disabled controls */ -static const unsigned ctrl_dis[] = { -[SEN_OV2610] = ((1 << NCTRL) - 1) /* no control */ - ^ ((1 << EXPOSURE) /* but exposure */ - | (1 << AUTOGAIN)), /* and autogain */ - -[SEN_OV2610AE] = ((1 << NCTRL) - 1) /* no control */ - ^ ((1 << EXPOSURE) /* but exposure */ - | (1 << AUTOGAIN)), /* and autogain */ - -[SEN_OV3610] = (1 << NCTRL) - 1, /* no control */ - -[SEN_OV6620] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV6630] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV66308AF] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7610] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7620] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7620AE] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7640] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << AUTOBRIGHT) | - (1 << CONTRAST) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7648] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << AUTOBRIGHT) | - (1 << CONTRAST) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7660] = (1 << AUTOBRIGHT) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV7670] = (1 << COLORS) | - (1 << AUTOBRIGHT) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV76BE] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN), - -[SEN_OV8610] = (1 << HFLIP) | - (1 << VFLIP) | - (1 << EXPOSURE) | - (1 << AUTOGAIN) | - (1 << FREQ), -[SEN_OV9600] = ((1 << NCTRL) - 1) /* no control */ - ^ ((1 << EXPOSURE) /* but exposure */ - | (1 << AUTOGAIN)), /* and autogain */ - }; static const struct v4l2_pix_format ov519_vga_mode[] = { @@ -3306,11 +3203,11 @@ static void ov519_set_fr(struct sd *sd) ov518_i2c_w(sd, OV7670_R11_CLKRC, clock); } -static void setautogain(struct gspca_dev *gspca_dev) +static void setautogain(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - i2c_w_mask(sd, 0x13, sd->ctrls[AUTOGAIN].val ? 0x05 : 0x00, 0x05); + i2c_w_mask(sd, 0x13, val ? 0x05 : 0x00, 0x05); } /* this function is called at probe time */ @@ -3351,8 +3248,6 @@ static int sd_config(struct gspca_dev *gspca_dev, break; } - gspca_dev->cam.ctrls = sd->ctrls; - sd->quality = QUALITY_DEF; sd->frame_rate = 15; return 0; @@ -3467,8 +3362,6 @@ static int sd_init(struct gspca_dev *gspca_dev) break; } - gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; - /* initialize the sensor */ switch (sd->sensor) { case SEN_OV2610: @@ -3494,8 +3387,6 @@ static int sd_init(struct gspca_dev *gspca_dev) break; case SEN_OV6630: case SEN_OV66308AF: - sd->ctrls[CONTRAST].def = 200; - /* The default is too low for the ov6630 */ write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)); break; default: @@ -3522,26 +3413,12 @@ static int sd_init(struct gspca_dev *gspca_dev) sd->gspca_dev.curr_mode = 1; /* 640x480 */ ov519_set_mode(sd); ov519_set_fr(sd); - sd->ctrls[COLORS].max = 4; /* 0..4 */ - sd->ctrls[COLORS].val = - sd->ctrls[COLORS].def = 2; - setcolors(gspca_dev); - sd->ctrls[CONTRAST].max = 6; /* 0..6 */ - sd->ctrls[CONTRAST].val = - sd->ctrls[CONTRAST].def = 3; - setcontrast(gspca_dev); - sd->ctrls[BRIGHTNESS].max = 6; /* 0..6 */ - sd->ctrls[BRIGHTNESS].val = - sd->ctrls[BRIGHTNESS].def = 3; - setbrightness(gspca_dev); sd_reset_snapshot(gspca_dev); ov51x_restart(sd); ov51x_stop(sd); /* not in win traces */ ov51x_led_control(sd, 0); break; case SEN_OV7670: - sd->ctrls[FREQ].max = 3; /* auto */ - sd->ctrls[FREQ].def = 3; write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)); break; case SEN_OV8610: @@ -4177,15 +4054,14 @@ static void mode_init_ov_sensor_regs(struct sd *sd) } /* this function works for bridge ov519 and sensors ov7660 and ov7670 only */ -static void sethvflip(struct gspca_dev *gspca_dev) +static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip) { struct sd *sd = (struct sd *) gspca_dev; if (sd->gspca_dev.streaming) reg_w(sd, OV519_R51_RESET1, 0x0f); /* block stream */ i2c_w_mask(sd, OV7670_R1E_MVFP, - OV7670_MVFP_MIRROR * sd->ctrls[HFLIP].val - | OV7670_MVFP_VFLIP * sd->ctrls[VFLIP].val, + OV7670_MVFP_MIRROR * hflip | OV7670_MVFP_VFLIP * vflip, OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP); if (sd->gspca_dev.streaming) reg_w(sd, OV519_R51_RESET1, 0x00); /* restart stream */ @@ -4333,23 +4209,6 @@ static int sd_start(struct gspca_dev *gspca_dev) set_ov_sensor_window(sd); - if (!(sd->gspca_dev.ctrl_dis & (1 << CONTRAST))) - setcontrast(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << BRIGHTNESS))) - setbrightness(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << EXPOSURE))) - setexposure(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << COLORS))) - setcolors(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & ((1 << HFLIP) | (1 << VFLIP)))) - sethvflip(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOBRIGHT))) - setautobright(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOGAIN))) - setautogain(gspca_dev); - if (!(sd->gspca_dev.ctrl_dis & (1 << FREQ))) - setfreq_i(sd); - /* Force clear snapshot state in case the snapshot button was pressed while we weren't streaming */ sd->snapshot_needs_reset = 1; @@ -4605,10 +4464,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* -- management routines -- */ -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int val; static const struct ov_i2c_regvals brit_7660[][7] = { {{0x0f, 0x6a}, {0x24, 0x40}, {0x25, 0x2b}, {0x26, 0x90}, {0x27, 0xe0}, {0x28, 0xe0}, {0x2c, 0xe0}}, @@ -4626,7 +4484,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) {0x27, 0x60}, {0x28, 0x60}, {0x2c, 0x60}} }; - val = sd->ctrls[BRIGHTNESS].val; switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: @@ -4640,9 +4497,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) break; case SEN_OV7620: case SEN_OV7620AE: - /* 7620 doesn't like manual changes when in auto mode */ - if (!sd->ctrls[AUTOBRIGHT].val) - i2c_w(sd, OV7610_REG_BRT, val); + i2c_w(sd, OV7610_REG_BRT, val); break; case SEN_OV7660: write_i2c_regvals(sd, brit_7660[val], @@ -4656,10 +4511,9 @@ static void setbrightness(struct gspca_dev *gspca_dev) } } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int val; static const struct ov_i2c_regvals contrast_7660[][31] = { {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0xa0}, {0x70, 0x58}, {0x71, 0x38}, {0x72, 0x30}, {0x73, 0x30}, @@ -4719,7 +4573,6 @@ static void setcontrast(struct gspca_dev *gspca_dev) {0x88, 0xf1}, {0x89, 0xf9}, {0x8a, 0xfd}}, }; - val = sd->ctrls[CONTRAST].val; switch (sd->sensor) { case SEN_OV7610: case SEN_OV6620: @@ -4760,18 +4613,16 @@ static void setcontrast(struct gspca_dev *gspca_dev) } } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - if (!sd->ctrls[AUTOGAIN].val) - i2c_w(sd, 0x10, sd->ctrls[EXPOSURE].val); + i2c_w(sd, 0x10, val); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int val; static const struct ov_i2c_regvals colors_7660[][6] = { {{0x4f, 0x28}, {0x50, 0x2a}, {0x51, 0x02}, {0x52, 0x0a}, {0x53, 0x19}, {0x54, 0x23}}, @@ -4785,7 +4636,6 @@ static void setcolors(struct gspca_dev *gspca_dev) {0x53, 0x66}, {0x54, 0x8e}}, }; - val = sd->ctrls[COLORS].val; switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: @@ -4819,34 +4669,18 @@ static void setcolors(struct gspca_dev *gspca_dev) } } -static void setautobright(struct gspca_dev *gspca_dev) +static void setautobright(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - i2c_w_mask(sd, 0x2d, sd->ctrls[AUTOBRIGHT].val ? 0x10 : 0x00, 0x10); + i2c_w_mask(sd, 0x2d, val ? 0x10 : 0x00, 0x10); } -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AUTOGAIN].val = val; - if (val) { - gspca_dev->ctrl_inac |= (1 << EXPOSURE); - } else { - gspca_dev->ctrl_inac &= ~(1 << EXPOSURE); - sd->ctrls[EXPOSURE].val = i2c_r(sd, 0x10); - } - if (gspca_dev->streaming) - setautogain(gspca_dev); - return gspca_dev->usb_err; -} - -static void setfreq_i(struct sd *sd) +static void setfreq_i(struct sd *sd, s32 val) { if (sd->sensor == SEN_OV7660 || sd->sensor == SEN_OV7670) { - switch (sd->ctrls[FREQ].val) { + switch (val) { case 0: /* Banding filter disabled */ i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_BFILT); break; @@ -4868,7 +4702,7 @@ static void setfreq_i(struct sd *sd) break; } } else { - switch (sd->ctrls[FREQ].val) { + switch (val) { case 0: /* Banding filter disabled */ i2c_w_mask(sd, 0x2d, 0x00, 0x04); i2c_w_mask(sd, 0x2a, 0x00, 0x80); @@ -4900,56 +4734,28 @@ static void setfreq_i(struct sd *sd) } } } -static void setfreq(struct gspca_dev *gspca_dev) + +static void setfreq(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - setfreq_i(sd); + setfreq_i(sd, val); /* Ugly but necessary */ if (sd->bridge == BRIDGE_W9968CF) w9968cf_set_crop_window(sd); } -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - case 3: - if (sd->sensor != SEN_OV7670) - return -EINVAL; - - strcpy((char *) menu->name, "Automatic"); - return 0; - } - break; - } - return -EINVAL; -} - static int sd_get_jcomp(struct gspca_dev *gspca_dev, struct v4l2_jpegcompression *jcomp) { struct sd *sd = (struct sd *) gspca_dev; if (sd->bridge != BRIDGE_W9968CF) - return -EINVAL; + return -ENOTTY; memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; + jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; return 0; @@ -4961,38 +4767,161 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; if (sd->bridge != BRIDGE_W9968CF) - return -EINVAL; + return -ENOTTY; + + v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality); + return 0; +} - if (gspca_dev->streaming) - return -EBUSY; +static int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; + gspca_dev->usb_err = 0; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + gspca_dev->exposure->val = i2c_r(sd, 0x10); + break; + } + return 0; +} + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + setfreq(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOBRIGHTNESS: + if (ctrl->is_new) + setautobright(gspca_dev, ctrl->val); + if (!ctrl->val && sd->brightness->is_new) + setbrightness(gspca_dev, sd->brightness->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + sethvflip(gspca_dev, ctrl->val, sd->vflip->val); + break; + case V4L2_CID_AUTOGAIN: + if (ctrl->is_new) + setautogain(gspca_dev, ctrl->val); + if (!ctrl->val && gspca_dev->exposure->is_new) + setexposure(gspca_dev, gspca_dev->exposure->val); + break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + return -EBUSY; /* Should never happen, as we grab the ctrl */ + } + return gspca_dev->usb_err; +} - /* Return resulting jcomp params to app */ - sd_get_jcomp(gspca_dev, jcomp); +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .g_volatile_ctrl = sd_g_volatile_ctrl, + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 10); + if (valid_controls[sd->sensor].has_brightness) + sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, + sd->sensor == SEN_OV7660 ? 6 : 255, 1, + sd->sensor == SEN_OV7660 ? 3 : 127); + if (valid_controls[sd->sensor].has_contrast) { + if (sd->sensor == SEN_OV7660) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 6, 1, 3); + else + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, + (sd->sensor == SEN_OV6630 || + sd->sensor == SEN_OV66308AF) ? 200 : 127); + } + if (valid_controls[sd->sensor].has_sat) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, + sd->sensor == SEN_OV7660 ? 4 : 255, 1, + sd->sensor == SEN_OV7660 ? 2 : 127); + if (valid_controls[sd->sensor].has_exposure) + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 255, 1, 127); + if (valid_controls[sd->sensor].has_hvflip) { + sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + } + if (valid_controls[sd->sensor].has_autobright) + sd->autobright = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOBRIGHTNESS, 0, 1, 1, 1); + if (valid_controls[sd->sensor].has_autogain) + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + if (valid_controls[sd->sensor].has_freq) { + if (sd->sensor == SEN_OV7670) + sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO); + else + sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0); + } + if (sd->bridge == BRIDGE_W9968CF) + sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, + QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF); + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + if (gspca_dev->autogain) + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, true); + if (sd->autobright) + v4l2_ctrl_auto_cluster(2, &sd->autobright, 0, false); + if (sd->hflip) + v4l2_ctrl_cluster(2, &sd->hflip); return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .dq_callback = sd_reset_snapshot, - .querymenu = sd_querymenu, .get_jcomp = sd_get_jcomp, .set_jcomp = sd_set_jcomp, #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) @@ -5052,6 +4981,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 80c81dd6d68b..bb09d7884b89 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -35,6 +35,7 @@ #include "gspca.h" #include <linux/fixp-arith.h> +#include <media/v4l2-ctrls.h> #define OV534_REG_ADDRESS 0xf1 /* sensor address */ #define OV534_REG_SUBADDR 0xf2 @@ -53,29 +54,28 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); MODULE_LICENSE("GPL"); -/* controls */ -enum e_ctrl { - HUE, - SATURATION, - BRIGHTNESS, - CONTRAST, - GAIN, - EXPOSURE, - AGC, - AWB, - AEC, - SHARPNESS, - HFLIP, - VFLIP, - LIGHTFREQ, - NCTRLS /* number of controls */ -}; - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *hue; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + struct { /* gain control cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; + struct v4l2_ctrl *autowhitebalance; + struct { /* exposure control cluster */ + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + }; + struct v4l2_ctrl *sharpness; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *plfreq; __u32 last_pts; u16 last_fid; @@ -89,181 +89,9 @@ enum sensors { NSENSORS }; -/* V4L2 controls supported by the driver */ -static void sethue(struct gspca_dev *gspca_dev); -static void setsaturation(struct gspca_dev *gspca_dev); -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setgain(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static void setagc(struct gspca_dev *gspca_dev); -static void setawb(struct gspca_dev *gspca_dev); -static void setaec(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); -static void sethvflip(struct gspca_dev *gspca_dev); -static void setlightfreq(struct gspca_dev *gspca_dev); - static int sd_start(struct gspca_dev *gspca_dev); static void sd_stopN(struct gspca_dev *gspca_dev); -static const struct ctrl sd_ctrls[] = { -[HUE] = { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = -90, - .maximum = 90, - .step = 1, - .default_value = 0, - }, - .set_control = sethue - }, -[SATURATION] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 64, - }, - .set_control = setsaturation - }, -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0, - }, - .set_control = setbrightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 32, - }, - .set_control = setcontrast - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Main Gain", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 20, - }, - .set_control = setgain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 120, - }, - .set_control = setexposure - }, -[AGC] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set_control = setagc - }, -[AWB] = { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set_control = setawb - }, -[AEC] = { - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set_control = setaec - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 0, - }, - .set_control = setsharpness - }, -[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "HFlip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "VFlip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -[LIGHTFREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light Frequency Filter", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = setlightfreq - }, -}; static const struct v4l2_pix_format ov772x_mode[] = { {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, @@ -972,12 +800,10 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "frame_rate: %d", r->fps); } -static void sethue(struct gspca_dev *gspca_dev) +static void sethue(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int val; - val = sd->ctrls[HUE].val; if (sd->sensor == SENSOR_OV767x) { /* TBD */ } else { @@ -1014,12 +840,10 @@ static void sethue(struct gspca_dev *gspca_dev) } } -static void setsaturation(struct gspca_dev *gspca_dev) +static void setsaturation(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int val; - val = sd->ctrls[SATURATION].val; if (sd->sensor == SENSOR_OV767x) { int i; static u8 color_tb[][6] = { @@ -1040,12 +864,10 @@ static void setsaturation(struct gspca_dev *gspca_dev) } } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - int val; - val = sd->ctrls[BRIGHTNESS].val; if (sd->sensor == SENSOR_OV767x) { if (val < 0) val = 0x80 - val; @@ -1055,27 +877,18 @@ static void setbrightness(struct gspca_dev *gspca_dev) } } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - u8 val; - val = sd->ctrls[CONTRAST].val; if (sd->sensor == SENSOR_OV767x) sccb_reg_write(gspca_dev, 0x56, val); /* contras */ else sccb_reg_write(gspca_dev, 0x9c, val); } -static void setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - if (sd->ctrls[AGC].val) - return; - - val = sd->ctrls[GAIN].val; switch (val & 0x30) { case 0x00: val &= 0x0f; @@ -1097,15 +910,15 @@ static void setgain(struct gspca_dev *gspca_dev) sccb_reg_write(gspca_dev, 0x00, val); } -static void setexposure(struct gspca_dev *gspca_dev) +static s32 getgain(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - u8 val; + return sccb_reg_read(gspca_dev, 0x00); +} - if (sd->ctrls[AEC].val) - return; +static void setexposure(struct gspca_dev *gspca_dev, s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; - val = sd->ctrls[EXPOSURE].val; if (sd->sensor == SENSOR_OV767x) { /* set only aec[9:2] */ @@ -1123,11 +936,23 @@ static void setexposure(struct gspca_dev *gspca_dev) } } -static void setagc(struct gspca_dev *gspca_dev) +static s32 getexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->ctrls[AGC].val) { + if (sd->sensor == SENSOR_OV767x) { + /* get only aec[9:2] */ + return sccb_reg_read(gspca_dev, 0x10); /* aech */ + } else { + u8 hi = sccb_reg_read(gspca_dev, 0x08); + u8 lo = sccb_reg_read(gspca_dev, 0x10); + return (hi << 8 | lo) >> 1; + } +} + +static void setagc(struct gspca_dev *gspca_dev, s32 val) +{ + if (val) { sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) | 0x04); sccb_reg_write(gspca_dev, 0x64, @@ -1137,16 +962,14 @@ static void setagc(struct gspca_dev *gspca_dev) sccb_reg_read(gspca_dev, 0x13) & ~0x04); sccb_reg_write(gspca_dev, 0x64, sccb_reg_read(gspca_dev, 0x64) & ~0x03); - - setgain(gspca_dev); } } -static void setawb(struct gspca_dev *gspca_dev) +static void setawb(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->ctrls[AWB].val) { + if (val) { sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) | 0x02); if (sd->sensor == SENSOR_OV772x) @@ -1161,7 +984,7 @@ static void setawb(struct gspca_dev *gspca_dev) } } -static void setaec(struct gspca_dev *gspca_dev) +static void setaec(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; u8 data; @@ -1169,31 +992,25 @@ static void setaec(struct gspca_dev *gspca_dev) data = sd->sensor == SENSOR_OV767x ? 0x05 : /* agc + aec */ 0x01; /* agc */ - if (sd->ctrls[AEC].val) + switch (val) { + case V4L2_EXPOSURE_AUTO: sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) | data); - else { + break; + case V4L2_EXPOSURE_MANUAL: sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) & ~data); - if (sd->sensor == SENSOR_OV767x) - sd->ctrls[EXPOSURE].val = - sccb_reg_read(gspca_dev, 10); /* aech */ - else - setexposure(gspca_dev); + break; } } -static void setsharpness(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - - val = sd->ctrls[SHARPNESS].val; sccb_reg_write(gspca_dev, 0x91, val); /* Auto de-noise threshold */ sccb_reg_write(gspca_dev, 0x8e, val); /* De-noise threshold */ } -static void sethvflip(struct gspca_dev *gspca_dev) +static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip) { struct sd *sd = (struct sd *) gspca_dev; u8 val; @@ -1201,28 +1018,27 @@ static void sethvflip(struct gspca_dev *gspca_dev) if (sd->sensor == SENSOR_OV767x) { val = sccb_reg_read(gspca_dev, 0x1e); /* mvfp */ val &= ~0x30; - if (sd->ctrls[HFLIP].val) + if (hflip) val |= 0x20; - if (sd->ctrls[VFLIP].val) + if (vflip) val |= 0x10; sccb_reg_write(gspca_dev, 0x1e, val); } else { val = sccb_reg_read(gspca_dev, 0x0c); val &= ~0xc0; - if (sd->ctrls[HFLIP].val == 0) + if (hflip == 0) val |= 0x40; - if (sd->ctrls[VFLIP].val == 0) + if (vflip == 0) val |= 0x80; sccb_reg_write(gspca_dev, 0x0c, val); } } -static void setlightfreq(struct gspca_dev *gspca_dev) +static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - u8 val; - val = sd->ctrls[LIGHTFREQ].val ? 0x9e : 0x00; + val = val ? 0x9e : 0x00; if (sd->sensor == SENSOR_OV767x) { sccb_reg_write(gspca_dev, 0x2a, 0x00); if (val) @@ -1241,8 +1057,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; - cam->ctrls = sd->ctrls; - cam->cam_mode = ov772x_mode; cam->nmodes = ARRAY_SIZE(ov772x_mode); @@ -1251,6 +1065,195 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } +static int ov534_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); + struct gspca_dev *gspca_dev = &sd->gspca_dev; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + gspca_dev->usb_err = 0; + if (ctrl->val && sd->gain && gspca_dev->streaming) + sd->gain->val = getgain(gspca_dev); + return gspca_dev->usb_err; + + case V4L2_CID_EXPOSURE_AUTO: + gspca_dev->usb_err = 0; + if (ctrl->val == V4L2_EXPOSURE_AUTO && sd->exposure && + gspca_dev->streaming) + sd->exposure->val = getexposure(gspca_dev); + return gspca_dev->usb_err; + } + return -EINVAL; +} + +static int ov534_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); + struct gspca_dev *gspca_dev = &sd->gspca_dev; + + gspca_dev->usb_err = 0; + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_HUE: + sethue(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setsaturation(gspca_dev, ctrl->val); + break; + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + /* case V4L2_CID_GAIN: */ + setagc(gspca_dev, ctrl->val); + if (!gspca_dev->usb_err && !ctrl->val && sd->gain) + setgain(gspca_dev, sd->gain->val); + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + setawb(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE_AUTO: + /* case V4L2_CID_EXPOSURE: */ + setaec(gspca_dev, ctrl->val); + if (!gspca_dev->usb_err && ctrl->val == V4L2_EXPOSURE_MANUAL && + sd->exposure) + setexposure(gspca_dev, sd->exposure->val); + break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + sethvflip(gspca_dev, ctrl->val, sd->vflip->val); + break; + case V4L2_CID_VFLIP: + sethvflip(gspca_dev, sd->hflip->val, ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + setlightfreq(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops ov534_ctrl_ops = { + .g_volatile_ctrl = ov534_g_volatile_ctrl, + .s_ctrl = ov534_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler; + /* parameters with different values between the supported sensors */ + int saturation_min; + int saturation_max; + int saturation_def; + int brightness_min; + int brightness_max; + int brightness_def; + int contrast_max; + int contrast_def; + int exposure_min; + int exposure_max; + int exposure_def; + int hflip_def; + + if (sd->sensor == SENSOR_OV767x) { + saturation_min = 0, + saturation_max = 6, + saturation_def = 3, + brightness_min = -127; + brightness_max = 127; + brightness_def = 0; + contrast_max = 0x80; + contrast_def = 0x40; + exposure_min = 0x08; + exposure_max = 0x60; + exposure_def = 0x13; + hflip_def = 1; + } else { + saturation_min = 0, + saturation_max = 255, + saturation_def = 64, + brightness_min = 0; + brightness_max = 255; + brightness_def = 0; + contrast_max = 255; + contrast_def = 32; + exposure_min = 0; + exposure_max = 255; + exposure_def = 120; + hflip_def = 0; + } + + gspca_dev->vdev.ctrl_handler = hdl; + + v4l2_ctrl_handler_init(hdl, 13); + + if (sd->sensor == SENSOR_OV772x) + sd->hue = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_HUE, -90, 90, 1, 0); + + sd->saturation = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_SATURATION, saturation_min, saturation_max, 1, + saturation_def); + sd->brightness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_BRIGHTNESS, brightness_min, brightness_max, 1, + brightness_def); + sd->contrast = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_CONTRAST, 0, contrast_max, 1, contrast_def); + + if (sd->sensor == SENSOR_OV772x) { + sd->autogain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + sd->gain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_GAIN, 0, 63, 1, 20); + } + + sd->autoexposure = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops, + V4L2_CID_EXPOSURE_AUTO, + V4L2_EXPOSURE_MANUAL, 0, + V4L2_EXPOSURE_AUTO); + sd->exposure = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_EXPOSURE, exposure_min, exposure_max, 1, + exposure_def); + + sd->autowhitebalance = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + + if (sd->sensor == SENSOR_OV772x) + sd->sharpness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 63, 1, 0); + + sd->hflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, hflip_def); + sd->vflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ, 0, + V4L2_CID_POWER_LINE_FREQUENCY_DISABLED); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + if (sd->sensor == SENSOR_OV772x) + v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true); + + v4l2_ctrl_auto_cluster(2, &sd->autoexposure, V4L2_EXPOSURE_MANUAL, + true); + + return 0; +} + /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { @@ -1286,24 +1289,6 @@ static int sd_init(struct gspca_dev *gspca_dev) if ((sensor_id & 0xfff0) == 0x7670) { sd->sensor = SENSOR_OV767x; - gspca_dev->ctrl_dis = (1 << HUE) | - (1 << GAIN) | - (1 << AGC) | - (1 << SHARPNESS); /* auto */ - sd->ctrls[SATURATION].min = 0, - sd->ctrls[SATURATION].max = 6, - sd->ctrls[SATURATION].def = 3, - sd->ctrls[BRIGHTNESS].min = -127; - sd->ctrls[BRIGHTNESS].max = 127; - sd->ctrls[BRIGHTNESS].def = 0; - sd->ctrls[CONTRAST].max = 0x80; - sd->ctrls[CONTRAST].def = 0x40; - sd->ctrls[EXPOSURE].min = 0x08; - sd->ctrls[EXPOSURE].max = 0x60; - sd->ctrls[EXPOSURE].def = 0x13; - sd->ctrls[SHARPNESS].max = 9; - sd->ctrls[SHARPNESS].def = 4; - sd->ctrls[HFLIP].def = 1; gspca_dev->cam.cam_mode = ov767x_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); } else { @@ -1366,22 +1351,23 @@ static int sd_start(struct gspca_dev *gspca_dev) set_frame_rate(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << HUE))) - sethue(gspca_dev); - setsaturation(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << AGC))) - setagc(gspca_dev); - setawb(gspca_dev); - setaec(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << GAIN))) - setgain(gspca_dev); - setexposure(gspca_dev); - setbrightness(gspca_dev); - setcontrast(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS))) - setsharpness(gspca_dev); - sethvflip(gspca_dev); - setlightfreq(gspca_dev); + if (sd->hue) + sethue(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue)); + setsaturation(gspca_dev, v4l2_ctrl_g_ctrl(sd->saturation)); + if (sd->autogain) + setagc(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain)); + setawb(gspca_dev, v4l2_ctrl_g_ctrl(sd->autowhitebalance)); + setaec(gspca_dev, v4l2_ctrl_g_ctrl(sd->autoexposure)); + if (sd->gain) + setgain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); + setbrightness(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness)); + setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast)); + if (sd->sharpness) + setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness)); + sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), + v4l2_ctrl_g_ctrl(sd->vflip)); + setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq)); ov534_set_led(gspca_dev, 1); ov534_reg_write(gspca_dev, 0xe0, 0x00); @@ -1483,25 +1469,6 @@ scan_next: } while (remaining_len > 0); } -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "Disabled"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - } - break; - } - - return -EINVAL; -} - /* get stream parameters (framerate) */ static void sd_get_streamparm(struct gspca_dev *gspca_dev, struct v4l2_streamparm *parm) @@ -1536,14 +1503,12 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, .get_streamparm = sd_get_streamparm, .set_streamparm = sd_set_streamparm, }; @@ -1572,6 +1537,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index 1fd41f0d2e95..c4cd028fe0b4 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c @@ -47,22 +47,9 @@ MODULE_AUTHOR("Jean-Francois Moine <moinejf@free.fr>"); MODULE_DESCRIPTION("GSPCA/OV534_9 USB Camera Driver"); MODULE_LICENSE("GPL"); -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - AUTOGAIN, - EXPOSURE, - SHARPNESS, - SATUR, - LIGHTFREQ, - NCTRLS /* number of controls */ -}; - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; __u32 last_pts; u8 last_fid; @@ -75,103 +62,6 @@ enum sensors { NSENSORS }; -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setautogain(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); -static void setsatur(struct gspca_dev *gspca_dev); -static void setlightfreq(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 7 - }, - .set_control = setbrightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 3 - }, - .set_control = setcontrast - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Autogain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set_control = setautogain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0 - }, - .set_control = setexposure - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = -1, /* -1 = auto */ - .maximum = 4, - .step = 1, - .default_value = -1 - }, - .set_control = setsharpness - }, -[SATUR] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 4, - .step = 1, - .default_value = 2 - }, - .set_control = setsatur - }, -[LIGHTFREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, - .default_value = 0 - }, - .set_control = setlightfreq - }, -}; - static const struct v4l2_pix_format ov965x_mode[] = { #define QVGA_MODE 0 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -1104,16 +994,14 @@ static void set_led(struct gspca_dev *gspca_dev, int status) } } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness) { struct sd *sd = (struct sd *) gspca_dev; u8 val; s8 sval; - if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) - return; if (sd->sensor == SENSOR_OV562x) { - sval = sd->ctrls[BRIGHTNESS].val; + sval = brightness; val = 0x76; val += sval; sccb_write(gspca_dev, 0x24, val); @@ -1128,7 +1016,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) val = 0xe6; sccb_write(gspca_dev, 0x26, val); } else { - val = sd->ctrls[BRIGHTNESS].val; + val = brightness; if (val < 8) val = 15 - val; /* f .. 8 */ else @@ -1138,43 +1026,32 @@ static void setbrightness(struct gspca_dev *gspca_dev) } } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << CONTRAST)) - return; sccb_write(gspca_dev, 0x56, /* cnst1 - contrast 1 ctrl coeff */ - sd->ctrls[CONTRAST].val << 4); + val << 4); } -static void setautogain(struct gspca_dev *gspca_dev) +static void setautogain(struct gspca_dev *gspca_dev, s32 autogain) { - struct sd *sd = (struct sd *) gspca_dev; u8 val; - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) - return; /*fixme: should adjust agc/awb/aec by different controls */ val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->ctrls[AUTOGAIN].val) + if (autogain) val |= 0x05; /* agc & aec */ else val &= 0xfa; sccb_write(gspca_dev, 0x13, val); } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 exposure) { - struct sd *sd = (struct sd *) gspca_dev; - u8 val; static const u8 expo[4] = {0x00, 0x25, 0x38, 0x5e}; + u8 val; - if (gspca_dev->ctrl_dis & (1 << EXPOSURE)) - return; - sccb_write(gspca_dev, 0x10, /* aec[9:2] */ - expo[sd->ctrls[EXPOSURE].val]); + sccb_write(gspca_dev, 0x10, expo[exposure]); /* aec[9:2] */ val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); @@ -1185,14 +1062,8 @@ static void setexposure(struct gspca_dev *gspca_dev) sccb_write(gspca_dev, 0xa1, val & 0xe0); /* aec[15:10] = 0 */ } -static void setsharpness(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - s8 val; - - if (gspca_dev->ctrl_dis & (1 << SHARPNESS)) - return; - val = sd->ctrls[SHARPNESS].val; if (val < 0) { /* auto */ val = sccb_read(gspca_dev, 0x42); /* com17 */ sccb_write(gspca_dev, 0xff, 0x00); @@ -1209,9 +1080,8 @@ static void setsharpness(struct gspca_dev *gspca_dev) sccb_write(gspca_dev, 0x42, val & 0xbf); } -static void setsatur(struct gspca_dev *gspca_dev) +static void setsatur(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 val1, val2, val3; static const u8 matrix[5][2] = { {0x14, 0x38}, @@ -1221,10 +1091,8 @@ static void setsatur(struct gspca_dev *gspca_dev) {0x48, 0x90} }; - if (gspca_dev->ctrl_dis & (1 << SATUR)) - return; - val1 = matrix[sd->ctrls[SATUR].val][0]; - val2 = matrix[sd->ctrls[SATUR].val][1]; + val1 = matrix[val][0]; + val2 = matrix[val][1]; val3 = val1 + val2; sccb_write(gspca_dev, 0x4f, val3); /* matrix coeff */ sccb_write(gspca_dev, 0x50, val3); @@ -1239,16 +1107,13 @@ static void setsatur(struct gspca_dev *gspca_dev) sccb_write(gspca_dev, 0x41, val1); } -static void setlightfreq(struct gspca_dev *gspca_dev) +static void setlightfreq(struct gspca_dev *gspca_dev, s32 freq) { - struct sd *sd = (struct sd *) gspca_dev; u8 val; - if (gspca_dev->ctrl_dis & (1 << LIGHTFREQ)) - return; val = sccb_read(gspca_dev, 0x13); /* com8 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->ctrls[LIGHTFREQ].val == 0) { + if (freq == 0) { sccb_write(gspca_dev, 0x13, val & 0xdf); return; } @@ -1256,7 +1121,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev) val = sccb_read(gspca_dev, 0x42); /* com17 */ sccb_write(gspca_dev, 0xff, 0x00); - if (sd->ctrls[LIGHTFREQ].val == 1) + if (freq == 1) val |= 0x01; else val &= 0xfe; @@ -1267,13 +1132,6 @@ static void setlightfreq(struct gspca_dev *gspca_dev) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; - - gspca_dev->cam.ctrls = sd->ctrls; - -#if AUTOGAIN_DEF != 0 - gspca_dev->ctrl_inac |= (1 << EXPOSURE); -#endif return 0; } @@ -1330,9 +1188,6 @@ static int sd_init(struct gspca_dev *gspca_dev) gspca_dev->cam.cam_mode = ov971x_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(ov971x_mode); - /* no control yet */ - gspca_dev->ctrl_dis = (1 << NCTRLS) - 1; - gspca_dev->cam.bulk = 1; gspca_dev->cam.bulk_size = 16384; gspca_dev->cam.bulk_nurbs = 2; @@ -1358,16 +1213,6 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x56, 0x17); } else if ((sensor_id & 0xfff0) == 0x5620) { sd->sensor = SENSOR_OV562x; - gspca_dev->ctrl_dis = (1 << CONTRAST) | - (1 << AUTOGAIN) | - (1 << EXPOSURE) | - (1 << SHARPNESS) | - (1 << SATUR) | - (1 << LIGHTFREQ); - - sd->ctrls[BRIGHTNESS].min = -90; - sd->ctrls[BRIGHTNESS].max = 90; - sd->ctrls[BRIGHTNESS].def = 0; gspca_dev->cam.cam_mode = ov562x_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode); @@ -1390,10 +1235,9 @@ static int sd_start(struct gspca_dev *gspca_dev) if (sd->sensor == SENSOR_OV971x) return gspca_dev->usb_err; - else if (sd->sensor == SENSOR_OV562x) { - setbrightness(gspca_dev); + if (sd->sensor == SENSOR_OV562x) return gspca_dev->usb_err; - } + switch (gspca_dev->curr_mode) { case QVGA_MODE: /* 320x240 */ sccb_w_array(gspca_dev, ov965x_start_1_vga, @@ -1437,13 +1281,6 @@ static int sd_start(struct gspca_dev *gspca_dev) ARRAY_SIZE(ov965x_start_2_sxga)); break; } - setlightfreq(gspca_dev); - setautogain(gspca_dev); - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setexposure(gspca_dev); - setsharpness(gspca_dev); - setsatur(gspca_dev); reg_w(gspca_dev, 0xe0, 0x00); reg_w(gspca_dev, 0xe0, 0x00); @@ -1541,38 +1378,94 @@ scan_next: } while (remaining_len > 0); } -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - switch (menu->id) { + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setsatur(gspca_dev, ctrl->val); + break; case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } + setlightfreq(gspca_dev, ctrl->val); break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + if (ctrl->is_new) + setautogain(gspca_dev, ctrl->val); + if (!ctrl->val && gspca_dev->exposure->is_new) + setexposure(gspca_dev, gspca_dev->exposure->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + if (sd->sensor == SENSOR_OV971x) + return 0; + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 7); + if (sd->sensor == SENSOR_OV562x) { + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, -90, 90, 1, 0); + } else { + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 15, 1, 7); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 15, 1, 3); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 4, 1, 2); + /* -1 = auto */ + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, -1, 4, 1, -1); + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 3, 1, 0); + v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0); + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); } - return -EINVAL; + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, }; /* -- module initialisation -- */ @@ -1600,6 +1493,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index fa661c6d6d55..d236d1791f78 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -462,6 +462,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index a0369a58c4bb..4877f7ab3d59 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -84,31 +84,31 @@ /* Include pac common sof detection functions */ #include "pac_common.h" +#define PAC7302_GAIN_DEFAULT 15 +#define PAC7302_GAIN_KNEE 42 +#define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */ +#define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ + MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, " "Thomas Kaiser thomas@kaiser-linux.li"); MODULE_DESCRIPTION("Pixart PAC7302"); MODULE_LICENSE("GPL"); -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - COLORS, - WHITE_BALANCE, - RED_BALANCE, - BLUE_BALANCE, - GAIN, - AUTOGAIN, - EXPOSURE, - VFLIP, - HFLIP, - NCTRLS /* number of controls */ -}; - struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; - + struct { /* brightness / contrast cluster */ + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + }; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *white_balance; + struct v4l2_ctrl *red_balance; + struct v4l2_ctrl *blue_balance; + struct { /* flip cluster */ + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + }; u8 flags; #define FL_HFLIP 0x01 /* mirrored by default */ #define FL_VFLIP 0x02 /* vertical flipped by default */ @@ -119,160 +119,6 @@ struct sd { atomic_t avg_lum; }; -/* V4L2 controls supported by the driver */ -static void setbrightcont(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void setwhitebalance(struct gspca_dev *gspca_dev); -static void setredbalance(struct gspca_dev *gspca_dev); -static void setbluebalance(struct gspca_dev *gspca_dev); -static void setgain(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static void setautogain(struct gspca_dev *gspca_dev); -static void sethvflip(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, -#define BRIGHTNESS_MAX 0x20 - .maximum = BRIGHTNESS_MAX, - .step = 1, - .default_value = 0x10, - }, - .set_control = setbrightcont - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, -#define CONTRAST_MAX 255 - .maximum = CONTRAST_MAX, - .step = 1, - .default_value = 127, - }, - .set_control = setbrightcont - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, -#define COLOR_MAX 255 - .maximum = COLOR_MAX, - .step = 1, - .default_value = 127 - }, - .set_control = setcolors - }, -[WHITE_BALANCE] = { - { - .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "White Balance", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 4, - }, - .set_control = setwhitebalance - }, -[RED_BALANCE] = { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 1, - }, - .set_control = setredbalance - }, -[BLUE_BALANCE] = { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 1, - }, - .set_control = setbluebalance - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 62, - .step = 1, -#define GAIN_DEF 15 -#define GAIN_KNEE 46 - .default_value = GAIN_DEF, - }, - .set_control = setgain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 1023, - .step = 1, -#define EXPOSURE_DEF 66 /* 33 ms / 30 fps */ -#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ - .default_value = EXPOSURE_DEF, - }, - .set_control = setexposure - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set_control = setautogain, - }, -[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip, - }, -[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 640, @@ -516,8 +362,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = vga_mode; /* only 640x480 */ cam->nmodes = ARRAY_SIZE(vga_mode); - gspca_dev->cam.ctrls = sd->ctrls; - sd->flags = id->driver_info; return 0; } @@ -536,9 +380,9 @@ static void setbrightcont(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ for (i = 0; i < 10; i++) { v = max[i]; - v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX) - * 150 / BRIGHTNESS_MAX; /* 200 ? */ - v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX; + v += (sd->brightness->val - sd->brightness->maximum) + * 150 / sd->brightness->maximum; /* 200 ? */ + v -= delta[i] * sd->contrast->val / sd->contrast->maximum; if (v < 0) v = 0; else if (v > 0xff) @@ -561,7 +405,8 @@ static void setcolors(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x11, 0x01); reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ for (i = 0; i < 9; i++) { - v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i]; + v = a[i] * sd->saturation->val / sd->saturation->maximum; + v += b[i]; reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); reg_w(gspca_dev, 0x0f + 2 * i + 1, v); } @@ -573,7 +418,7 @@ static void setwhitebalance(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val); + reg_w(gspca_dev, 0xc6, sd->white_balance->val); reg_w(gspca_dev, 0xdc, 0x01); } @@ -583,7 +428,7 @@ static void setredbalance(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val); + reg_w(gspca_dev, 0xc5, sd->red_balance->val); reg_w(gspca_dev, 0xdc, 0x01); } @@ -593,22 +438,21 @@ static void setbluebalance(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val); + reg_w(gspca_dev, 0xc7, sd->blue_balance->val); reg_w(gspca_dev, 0xdc, 0x01); } static void setgain(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; u8 reg10, reg12; - if (sd->ctrls[GAIN].val < 32) { - reg10 = sd->ctrls[GAIN].val; + if (gspca_dev->gain->val < 32) { + reg10 = gspca_dev->gain->val; reg12 = 0; } else { reg10 = 31; - reg12 = sd->ctrls[GAIN].val - 31; + reg12 = gspca_dev->gain->val - 31; } reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ @@ -621,7 +465,6 @@ static void setgain(struct gspca_dev *gspca_dev) static void setexposure(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; u8 clockdiv; u16 exposure; @@ -630,7 +473,7 @@ static void setexposure(struct gspca_dev *gspca_dev) * no fps according to the formula: 90 / reg. sd->exposure is the * desired exposure time in 0.5 ms. */ - clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000; + clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000; /* * Note clockdiv = 3 also works, but when running at 30 fps, depending @@ -655,7 +498,7 @@ static void setexposure(struct gspca_dev *gspca_dev) * frame exposure time in ms = 1000 * clockdiv / 90 -> * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ - exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv); + exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv); /* 0 = use full frametime, 448 = no exposure, reverse it */ exposure = 448 - exposure; @@ -668,37 +511,15 @@ static void setexposure(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x11, 0x01); } -static void setautogain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* - * When switching to autogain set defaults to make sure - * we are on a valid point of the autogain gain / - * exposure knee graph, and give this change time to - * take effect before doing autogain. - */ - if (sd->ctrls[AUTOGAIN].val) { - sd->ctrls[EXPOSURE].val = EXPOSURE_DEF; - sd->ctrls[GAIN].val = GAIN_DEF; - sd->autogain_ignore_frames = - PAC_AUTOGAIN_IGNORE_FRAMES; - } else { - sd->autogain_ignore_frames = -1; - } - setexposure(gspca_dev); - setgain(gspca_dev); -} - static void sethvflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; u8 data, hflip, vflip; - hflip = sd->ctrls[HFLIP].val; + hflip = sd->hflip->val; if (sd->flags & FL_HFLIP) hflip = !hflip; - vflip = sd->ctrls[VFLIP].val; + vflip = sd->vflip->val; if (sd->flags & FL_VFLIP) vflip = !vflip; @@ -717,6 +538,112 @@ static int sd_init(struct gspca_dev *gspca_dev) return gspca_dev->usb_err; } +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) { + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT; + gspca_dev->gain->val = PAC7302_GAIN_DEFAULT; + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; + } + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightcont(gspca_dev); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev); + break; + case V4L2_CID_WHITE_BALANCE_TEMPERATURE: + setwhitebalance(gspca_dev); + break; + case V4L2_CID_RED_BALANCE: + setredbalance(gspca_dev); + break; + case V4L2_CID_BLUE_BALANCE: + setbluebalance(gspca_dev); + break; + case V4L2_CID_AUTOGAIN: + if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val)) + setexposure(gspca_dev); + if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val)) + setgain(gspca_dev); + break; + case V4L2_CID_HFLIP: + sethvflip(gspca_dev); + break; + default: + return -EINVAL; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +/* this function is called at probe time */ +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 11); + + sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 32, 1, 16); + sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 127); + + sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 127); + sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_WHITE_BALANCE_TEMPERATURE, + 0, 255, 1, 4); + sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 3, 1, 1); + sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 3, 1, 1); + + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 1023, 1, + PAC7302_EXPOSURE_DEFAULT); + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 62, 1, + PAC7302_GAIN_DEFAULT); + + sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + v4l2_ctrl_cluster(2, &sd->brightness); + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); + v4l2_ctrl_cluster(2, &sd->hflip); + return 0; +} + +/* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -728,11 +655,13 @@ static int sd_start(struct gspca_dev *gspca_dev) setwhitebalance(gspca_dev); setredbalance(gspca_dev); setbluebalance(gspca_dev); - setautogain(gspca_dev); + setexposure(gspca_dev); + setgain(gspca_dev); sethvflip(gspca_dev); sd->sof_read = 0; - atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val); + sd->autogain_ignore_frames = 0; + atomic_set(&sd->avg_lum, 270 + sd->brightness->val); /* start stream */ reg_w(gspca_dev, 0xff, 0x01); @@ -758,9 +687,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x78, 0x40); } -#define WANT_REGULAR_AUTOGAIN -#include "autogain_functions.h" - static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -774,11 +700,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) if (sd->autogain_ignore_frames > 0) { sd->autogain_ignore_frames--; } else { - desired_lum = 270 + sd->ctrls[BRIGHTNESS].val; + desired_lum = 270 + sd->brightness->val; - auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, - deadzone, GAIN_KNEE, EXPOSURE_KNEE); - sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; + if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum, + deadzone, PAC7302_GAIN_KNEE, + PAC7302_EXPOSURE_KNEE)) + sd->autogain_ignore_frames = + PAC_AUTOGAIN_IGNORE_FRAMES; } } @@ -944,10 +872,9 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, /* sub-driver description for pac7302 */ static const struct sd_desc sd_desc = { .name = KBUILD_MODNAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, @@ -998,6 +925,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index 115da169f32a..ba3558d3f017 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -694,6 +694,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c index bb70092c2229..a33cb78a839c 100644 --- a/drivers/media/video/gspca/se401.c +++ b/drivers/media/video/gspca/se401.c @@ -45,15 +45,6 @@ MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_DESCRIPTION("Endpoints se401"); MODULE_LICENSE("GPL"); -/* controls */ -enum e_ctrl { - BRIGHTNESS, - GAIN, - EXPOSURE, - FREQ, - NCTRL /* number of controls */ -}; - /* exposure change state machine states */ enum { EXPO_CHANGED, @@ -64,7 +55,11 @@ enum { /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRL]; + struct { /* exposure/freq control cluster */ + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *freq; + }; + bool has_brightness; struct v4l2_pix_format fmts[MAX_MODES]; int pixels_read; int packet_read; @@ -77,60 +72,6 @@ struct sd { int expo_change_state; }; -static void setbrightness(struct gspca_dev *gspca_dev); -static void setgain(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRL] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 15, - }, - .set_control = setbrightness - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 50, /* Really 63 but > 50 is not pretty */ - .step = 1, - .default_value = 25, - }, - .set_control = setgain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 32767, - .step = 1, - .default_value = 15000, - }, - .set_control = setexposure - }, -[FREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, - .step = 1, - .default_value = 0, - }, - .set_control = setexposure - }, -}; static void se401_write_req(struct gspca_dev *gspca_dev, u16 req, u16 value, int silent) @@ -224,22 +165,15 @@ static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector) return gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8); } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS)) - return; - /* HDG: this does not seem to do anything on my cam */ - se401_write_req(gspca_dev, SE401_REQ_SET_BRT, - sd->ctrls[BRIGHTNESS].val, 0); + se401_write_req(gspca_dev, SE401_REQ_SET_BRT, val, 0); } -static void setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - u16 gain = 63 - sd->ctrls[GAIN].val; + u16 gain = 63 - val; /* red color gain */ se401_set_feature(gspca_dev, HV7131_REG_ARCG, gain); @@ -249,10 +183,10 @@ static void setgain(struct gspca_dev *gspca_dev) se401_set_feature(gspca_dev, HV7131_REG_ABCG, gain); } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 val, s32 freq) { struct sd *sd = (struct sd *) gspca_dev; - int integration = sd->ctrls[EXPOSURE].val << 6; + int integration = val << 6; u8 expose_h, expose_m, expose_l; /* Do this before the set_feature calls, for proper timing wrt @@ -262,9 +196,9 @@ static void setexposure(struct gspca_dev *gspca_dev) through so be it */ sd->expo_change_state = EXPO_CHANGED; - if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) + if (freq == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) integration = integration - integration % 106667; - if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ) + if (freq == V4L2_CID_POWER_LINE_FREQUENCY_60HZ) integration = integration - integration % 88889; expose_h = (integration >> 16); @@ -375,15 +309,12 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->bulk = 1; cam->bulk_size = BULK_SIZE; cam->bulk_nurbs = 4; - cam->ctrls = sd->ctrls; sd->resetlevel = 0x2d; /* Set initial resetlevel */ /* See if the camera supports brightness */ se401_read_req(gspca_dev, SE401_REQ_GET_BRT, 1); - if (gspca_dev->usb_err) { - gspca_dev->ctrl_dis = (1 << BRIGHTNESS); - gspca_dev->usb_err = 0; - } + sd->has_brightness = !!gspca_dev->usb_err; + gspca_dev->usb_err = 0; return 0; } @@ -442,9 +373,6 @@ static int sd_start(struct gspca_dev *gspca_dev) } se401_set_feature(gspca_dev, SE401_OPERATINGMODE, mode); - setbrightness(gspca_dev); - setgain(gspca_dev); - setexposure(gspca_dev); se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel); sd->packet_read = 0; @@ -666,27 +594,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) sd_pkt_scan_janggu(gspca_dev, data, len); } -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: - strcpy((char *) menu->name, "NoFliker"); - return 0; - case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: - strcpy((char *) menu->name, "50 Hz"); - return 0; - case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - } - return -EINVAL; -} - #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) { @@ -714,19 +621,73 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len) } #endif +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + setgain(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + setexposure(gspca_dev, ctrl->val, sd->freq->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + if (sd->has_brightness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 15); + /* max is really 63 but > 50 is not pretty */ + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 50, 1, 25); + sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 32767, 1, 15000); + sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + v4l2_ctrl_cluster(2, &sd->exposure); + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .dq_callback = sd_dq_callback, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) .int_pkt_scan = sd_int_pkt_scan, #endif @@ -769,6 +730,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif .pre_reset = sd_pre_reset, .post_reset = sd_post_reset, diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/video/gspca/sn9c2028.c index 478533cb1152..03fa3fd940b4 100644 --- a/drivers/media/video/gspca/sn9c2028.c +++ b/drivers/media/video/gspca/sn9c2028.c @@ -40,10 +40,6 @@ struct init_command { unsigned char to_read; /* length to read. 0 means no reply requested */ }; -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[] = { -}; - /* How to change the resolution of any of the VGA cams is unknown */ static const struct v4l2_pix_format vga_mode[] = { {640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE, @@ -695,8 +691,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, .start = sd_start, @@ -734,6 +728,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 6c31e46a1fd2..b9c6f17eabb2 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -2070,10 +2070,13 @@ static int sd_start(struct gspca_dev *gspca_dev) set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma)); set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue), v4l2_ctrl_g_ctrl(sd->red)); - set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); - set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); - set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), - v4l2_ctrl_g_ctrl(sd->vflip)); + if (sd->gain) + set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); + if (sd->exposure) + set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); + if (sd->hflip) + set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), + v4l2_ctrl_g_ctrl(sd->vflip)); reg_w1(gspca_dev, 0x1007, 0x20); reg_w1(gspca_dev, 0x1061, 0x03); @@ -2176,7 +2179,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int avg_lum; - if (!v4l2_ctrl_g_ctrl(sd->autogain)) + if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain)) return; avg_lum = atomic_read(&sd->avg_lum); diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index e2bdf8f632f4..fd1f8d2d3b0b 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -56,26 +56,16 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver"); MODULE_LICENSE("GPL"); -/* controls */ -enum e_ctrl { - BRIGHTNESS, - GAIN, - EXPOSURE, - AUTOGAIN, - FREQ, - NCTRLS /* number of controls */ -}; - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *plfreq; atomic_t avg_lum; int prev_avg_lum; - int exp_too_low_cnt; - int exp_too_high_cnt; + int exposure_knee; int header_read; u8 header[12]; /* Header without sof marker */ @@ -107,24 +97,16 @@ struct sensor_data { sensor_init_t *sensor_init; int sensor_init_size; int flags; - unsigned ctrl_dis; __u8 sensor_addr; }; /* sensor_data flags */ -#define F_GAIN 0x01 /* has gain */ -#define F_SIF 0x02 /* sif or vga */ -#define F_COARSE_EXPO 0x04 /* exposure control is coarse */ +#define F_SIF 0x01 /* sif or vga */ /* priv field of struct v4l2_pix_format flags (do not use low nibble!) */ #define MODE_RAW 0x10 /* raw bayer mode */ #define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */ -/* ctrl_dis helper macros */ -#define NO_EXPO ((1 << EXPOSURE) | (1 << AUTOGAIN)) -#define NO_FREQ (1 << FREQ) -#define NO_BRIGHTNESS (1 << BRIGHTNESS) - #define COMP 0xc7 /* 0x87 //0x07 */ #define COMP1 0xc9 /* 0x89 //0x09 */ @@ -133,12 +115,12 @@ struct sensor_data { #define SYS_CLK 0x04 -#define SENS(bridge, sensor, _flags, _ctrl_dis, _sensor_addr) \ +#define SENS(bridge, sensor, _flags, _sensor_addr) \ { \ .bridge_init = bridge, \ .sensor_init = sensor, \ .sensor_init_size = sizeof(sensor), \ - .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \ + .flags = _flags, .sensor_addr = _sensor_addr \ } /* We calculate the autogain at the end of the transfer of a frame, at this @@ -147,87 +129,6 @@ struct sensor_data { the new settings to come into effect before doing any other adjustments. */ #define AUTOGAIN_IGNORE_FRAMES 1 -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setgain(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static void setfreq(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setbrightness - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 255, - .step = 1, -#define GAIN_KNEE 230 - .default_value = 127, - }, - .set_control = setgain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 1023, - .step = 1, - .default_value = 66, - /* 33 ms / 30 fps (except on PASXXX) */ -#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */ - .flags = 0, - }, - .set_control = setexposure - }, -/* for coarse exposure */ -#define COARSE_EXPOSURE_MIN 2 -#define COARSE_EXPOSURE_MAX 15 -#define COARSE_EXPOSURE_DEF 2 /* 30 fps */ -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain (and Exposure)", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - .flags = V4L2_CTRL_FLAG_UPDATE - }, - .set = sd_setautogain, - }, -[FREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, -#define FREQ_DEF 0 - .default_value = FREQ_DEF, - }, - .set_control = setfreq - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 160, @@ -532,25 +433,27 @@ static const __u8 tas5130_sensor_init[][8] = { }; static const struct sensor_data sensor_data[] = { -SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), -SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60), -SENS(initOv7630, ov7630_sensor_init, F_GAIN, 0, 0x21), -SENS(initPas106, pas106_sensor_init, F_GAIN|F_SIF, NO_FREQ, 0), -SENS(initPas202, pas202_sensor_init, F_GAIN, NO_FREQ, 0), -SENS(initTas5110c, tas5110c_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, - NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initTas5110d, tas5110d_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO, - NO_BRIGHTNESS|NO_FREQ, 0), -SENS(initTas5130, tas5130_sensor_init, F_GAIN, - NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), + SENS(initHv7131d, hv7131d_sensor_init, 0, 0), + SENS(initHv7131r, hv7131r_sensor_init, 0, 0), + SENS(initOv6650, ov6650_sensor_init, F_SIF, 0x60), + SENS(initOv7630, ov7630_sensor_init, 0, 0x21), + SENS(initPas106, pas106_sensor_init, F_SIF, 0), + SENS(initPas202, pas202_sensor_init, 0, 0), + SENS(initTas5110c, tas5110c_sensor_init, F_SIF, 0), + SENS(initTas5110d, tas5110d_sensor_init, F_SIF, 0), + SENS(initTas5130, tas5130_sensor_init, 0, 0), }; /* get one byte in gspca_dev->usb_buf */ static void reg_r(struct gspca_dev *gspca_dev, __u16 value) { - usb_control_msg(gspca_dev->dev, + int res; + + if (gspca_dev->usb_err < 0) + return; + + res = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), 0, /* request */ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, @@ -558,6 +461,12 @@ static void reg_r(struct gspca_dev *gspca_dev, 0, /* index */ gspca_dev->usb_buf, 1, 500); + + if (res < 0) { + dev_err(gspca_dev->v4l2_dev.dev, + "Error reading register %02x: %d\n", value, res); + gspca_dev->usb_err = res; + } } static void reg_w(struct gspca_dev *gspca_dev, @@ -565,14 +474,13 @@ static void reg_w(struct gspca_dev *gspca_dev, const __u8 *buffer, int len) { -#ifdef GSPCA_DEBUG - if (len > USB_BUF_SZ) { - PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); + int res; + + if (gspca_dev->usb_err < 0) return; - } -#endif + memcpy(gspca_dev->usb_buf, buffer, len); - usb_control_msg(gspca_dev->dev, + res = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0x08, /* request */ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, @@ -580,30 +488,48 @@ static void reg_w(struct gspca_dev *gspca_dev, 0, /* index */ gspca_dev->usb_buf, len, 500); + + if (res < 0) { + dev_err(gspca_dev->v4l2_dev.dev, + "Error writing register %02x: %d\n", value, res); + gspca_dev->usb_err = res; + } } -static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) +static void i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) { int retry = 60; + if (gspca_dev->usb_err < 0) + return; + /* is i2c ready */ reg_w(gspca_dev, 0x08, buffer, 8); while (retry--) { + if (gspca_dev->usb_err < 0) + return; msleep(10); reg_r(gspca_dev, 0x08); if (gspca_dev->usb_buf[0] & 0x04) { - if (gspca_dev->usb_buf[0] & 0x08) - return -1; - return 0; + if (gspca_dev->usb_buf[0] & 0x08) { + dev_err(gspca_dev->v4l2_dev.dev, + "i2c write error\n"); + gspca_dev->usb_err = -EIO; + } + return; } } - return -1; + + dev_err(gspca_dev->v4l2_dev.dev, "i2c write timeout\n"); + gspca_dev->usb_err = -EIO; } static void i2c_w_vector(struct gspca_dev *gspca_dev, const __u8 buffer[][8], int len) { for (;;) { + if (gspca_dev->usb_err < 0) + return; reg_w(gspca_dev, 0x08, *buffer, 8); len -= 8; if (len <= 0) @@ -624,11 +550,10 @@ static void setbrightness(struct gspca_dev *gspca_dev) /* change reg 0x06 */ i2cOV[1] = sensor_data[sd->sensor].sensor_addr; - i2cOV[3] = sd->ctrls[BRIGHTNESS].val; - if (i2c_w(gspca_dev, i2cOV) < 0) - goto err; + i2cOV[3] = sd->brightness->val; + i2c_w(gspca_dev, i2cOV); break; - } + } case SENSOR_PAS106: case SENSOR_PAS202: { __u8 i2cpbright[] = @@ -642,54 +567,49 @@ static void setbrightness(struct gspca_dev *gspca_dev) i2cpdoit[2] = 0x13; } - if (sd->ctrls[BRIGHTNESS].val < 127) { + if (sd->brightness->val < 127) { /* change reg 0x0b, signreg */ i2cpbright[3] = 0x01; /* set reg 0x0c, offset */ - i2cpbright[4] = 127 - sd->ctrls[BRIGHTNESS].val; + i2cpbright[4] = 127 - sd->brightness->val; } else - i2cpbright[4] = sd->ctrls[BRIGHTNESS].val - 127; + i2cpbright[4] = sd->brightness->val - 127; - if (i2c_w(gspca_dev, i2cpbright) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpdoit) < 0) - goto err; + i2c_w(gspca_dev, i2cpbright); + i2c_w(gspca_dev, i2cpdoit); + break; + } + default: break; - } } - return; -err: - PDEBUG(D_ERR, "i2c error brightness"); } -static void setsensorgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - u8 gain = sd->ctrls[GAIN].val; + u8 gain = gspca_dev->gain->val; switch (sd->sensor) { case SENSOR_HV7131D: { __u8 i2c[] = {0xc0, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x17}; - i2c[3] = 0x3f - (gain / 4); - i2c[4] = 0x3f - (gain / 4); - i2c[5] = 0x3f - (gain / 4); + i2c[3] = 0x3f - gain; + i2c[4] = 0x3f - gain; + i2c[5] = 0x3f - gain; - if (i2c_w(gspca_dev, i2c) < 0) - goto err; + i2c_w(gspca_dev, i2c); break; - } + } case SENSOR_TAS5110C: case SENSOR_TAS5130CXX: { __u8 i2c[] = {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}; i2c[4] = 255 - gain; - if (i2c_w(gspca_dev, i2c) < 0) - goto err; + i2c_w(gspca_dev, i2c); break; - } + } case SENSOR_TAS5110D: { __u8 i2c[] = { 0xb0, 0x61, 0x02, 0x00, 0x10, 0x00, 0x00, 0x17 }; @@ -703,23 +623,25 @@ static void setsensorgain(struct gspca_dev *gspca_dev) i2c[3] |= (gain & 0x04) << 3; i2c[3] |= (gain & 0x02) << 5; i2c[3] |= (gain & 0x01) << 7; - if (i2c_w(gspca_dev, i2c) < 0) - goto err; + i2c_w(gspca_dev, i2c); break; - } - + } case SENSOR_OV6650: - gain >>= 1; - /* fall thru */ case SENSOR_OV7630: { __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; + /* + * The ov7630's gain is weird, at 32 the gain drops to the + * same level as at 16, so skip 32-47 (of the 0-63 scale). + */ + if (sd->sensor == SENSOR_OV7630 && gain >= 32) + gain += 16; + i2c[1] = sensor_data[sd->sensor].sensor_addr; - i2c[3] = gain >> 2; - if (i2c_w(gspca_dev, i2c) < 0) - goto err; + i2c[3] = gain; + i2c_w(gspca_dev, i2c); break; - } + } case SENSOR_PAS106: case SENSOR_PAS202: { __u8 i2cpgain[] = @@ -737,49 +659,27 @@ static void setsensorgain(struct gspca_dev *gspca_dev) i2cpdoit[2] = 0x13; } - i2cpgain[3] = gain >> 3; - i2cpcolorgain[3] = gain >> 4; - i2cpcolorgain[4] = gain >> 4; - i2cpcolorgain[5] = gain >> 4; - i2cpcolorgain[6] = gain >> 4; - - if (i2c_w(gspca_dev, i2cpgain) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpcolorgain) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpdoit) < 0) - goto err; - break; - } - } - return; -err: - PDEBUG(D_ERR, "i2c error gain"); -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 gain; - __u8 buf[3] = { 0, 0, 0 }; + i2cpgain[3] = gain; + i2cpcolorgain[3] = gain >> 1; + i2cpcolorgain[4] = gain >> 1; + i2cpcolorgain[5] = gain >> 1; + i2cpcolorgain[6] = gain >> 1; - if (sensor_data[sd->sensor].flags & F_GAIN) { - /* Use the sensor gain to do the actual gain */ - setsensorgain(gspca_dev); - return; + i2c_w(gspca_dev, i2cpgain); + i2c_w(gspca_dev, i2cpcolorgain); + i2c_w(gspca_dev, i2cpdoit); + break; } - - if (sd->bridge == BRIDGE_103) { - gain = sd->ctrls[GAIN].val >> 1; - buf[0] = gain; /* Red */ - buf[1] = gain; /* Green */ - buf[2] = gain; /* Blue */ - reg_w(gspca_dev, 0x05, buf, 3); - } else { - gain = sd->ctrls[GAIN].val >> 4; - buf[0] = gain << 4 | gain; /* Red and blue */ - buf[1] = gain; /* Green */ - reg_w(gspca_dev, 0x10, buf, 2); + default: + if (sd->bridge == BRIDGE_103) { + u8 buf[3] = { gain, gain, gain }; /* R, G, B */ + reg_w(gspca_dev, 0x05, buf, 3); + } else { + u8 buf[2]; + buf[0] = gain << 4 | gain; /* Red and blue */ + buf[1] = gain; /* Green */ + reg_w(gspca_dev, 0x10, buf, 2); + } } } @@ -792,31 +692,24 @@ static void setexposure(struct gspca_dev *gspca_dev) /* Note the datasheet wrongly says line mode exposure uses reg 0x26 and 0x27, testing has shown 0x25 + 0x26 */ __u8 i2c[] = {0xc0, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x17}; - /* The HV7131D's exposure goes from 0 - 65535, we scale our - exposure of 0-1023 to 0-6138. There are 2 reasons for this: - 1) This puts our exposure knee of 200 at approx the point - where the framerate starts dropping - 2) At 6138 the framerate has already dropped to 2 fps, - going any lower makes little sense */ - u16 reg = sd->ctrls[EXPOSURE].val * 6; + u16 reg = gspca_dev->exposure->val; i2c[3] = reg >> 8; i2c[4] = reg & 0xff; - if (i2c_w(gspca_dev, i2c) != 0) - goto err; + i2c_w(gspca_dev, i2c); break; - } + } case SENSOR_TAS5110C: case SENSOR_TAS5110D: { /* register 19's high nibble contains the sn9c10x clock divider The high nibble configures the no fps according to the formula: 60 / high_nibble. With a maximum of 30 fps */ - u8 reg = sd->ctrls[EXPOSURE].val; + u8 reg = gspca_dev->exposure->val; reg = (reg << 4) | 0x0b; reg_w(gspca_dev, 0x19, ®, 1); break; - } + } case SENSOR_OV6650: case SENSOR_OV7630: { /* The ov6650 / ov7630 have 2 registers which both influence @@ -848,7 +741,7 @@ static void setexposure(struct gspca_dev *gspca_dev) } else reg10_max = 0x41; - reg11 = (15 * sd->ctrls[EXPOSURE].val + 999) / 1000; + reg11 = (15 * gspca_dev->exposure->val + 999) / 1000; if (reg11 < 1) reg11 = 1; else if (reg11 > 16) @@ -861,16 +754,16 @@ static void setexposure(struct gspca_dev *gspca_dev) reg11 = 4; /* frame exposure time in ms = 1000 * reg11 / 30 -> - reg10 = (sd->ctrls[EXPOSURE].val / 2) * reg10_max + reg10 = (gspca_dev->exposure->val / 2) * reg10_max / (1000 * reg11 / 30) */ - reg10 = (sd->ctrls[EXPOSURE].val * 15 * reg10_max) + reg10 = (gspca_dev->exposure->val * 15 * reg10_max) / (1000 * reg11); /* Don't allow this to get below 10 when using autogain, the steps become very large (relatively) when below 10 causing the image to oscilate from much too dark, to much too bright and back again. */ - if (sd->ctrls[AUTOGAIN].val && reg10 < 10) + if (gspca_dev->autogain->val && reg10 < 10) reg10 = 10; else if (reg10 > reg10_max) reg10 = reg10_max; @@ -884,12 +777,11 @@ static void setexposure(struct gspca_dev *gspca_dev) if (sd->reg11 == reg11) i2c[0] = 0xa0; - if (i2c_w(gspca_dev, i2c) == 0) + i2c_w(gspca_dev, i2c); + if (gspca_dev->usb_err == 0) sd->reg11 = reg11; - else - goto err; break; - } + } case SENSOR_PAS202: { __u8 i2cpframerate[] = {0xb0, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x16}; @@ -909,28 +801,25 @@ static void setexposure(struct gspca_dev *gspca_dev) frame exposure times (like we are doing with the ov chips), as that sometimes leads to jumps in the exposure control, which are bad for auto exposure. */ - if (sd->ctrls[EXPOSURE].val < 200) { - i2cpexpo[3] = 255 - (sd->ctrls[EXPOSURE].val * 255) + if (gspca_dev->exposure->val < 200) { + i2cpexpo[3] = 255 - (gspca_dev->exposure->val * 255) / 200; framerate_ctrl = 500; } else { /* The PAS202's exposure control goes from 0 - 4095, but anything below 500 causes vsync issues, so scale our 200-1023 to 500-4095 */ - framerate_ctrl = (sd->ctrls[EXPOSURE].val - 200) + framerate_ctrl = (gspca_dev->exposure->val - 200) * 1000 / 229 + 500; } i2cpframerate[3] = framerate_ctrl >> 6; i2cpframerate[4] = framerate_ctrl & 0x3f; - if (i2c_w(gspca_dev, i2cpframerate) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpexpo) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpdoit) < 0) - goto err; + i2c_w(gspca_dev, i2cpframerate); + i2c_w(gspca_dev, i2cpexpo); + i2c_w(gspca_dev, i2cpdoit); break; - } + } case SENSOR_PAS106: { __u8 i2cpframerate[] = {0xb1, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14}; @@ -942,46 +831,40 @@ static void setexposure(struct gspca_dev *gspca_dev) /* For values below 150 use partial frame exposure, above that use framerate ctrl */ - if (sd->ctrls[EXPOSURE].val < 150) { - i2cpexpo[3] = 150 - sd->ctrls[EXPOSURE].val; + if (gspca_dev->exposure->val < 150) { + i2cpexpo[3] = 150 - gspca_dev->exposure->val; framerate_ctrl = 300; } else { /* The PAS106's exposure control goes from 0 - 4095, but anything below 300 causes vsync issues, so scale our 150-1023 to 300-4095 */ - framerate_ctrl = (sd->ctrls[EXPOSURE].val - 150) + framerate_ctrl = (gspca_dev->exposure->val - 150) * 1000 / 230 + 300; } i2cpframerate[3] = framerate_ctrl >> 4; i2cpframerate[4] = framerate_ctrl & 0x0f; - if (i2c_w(gspca_dev, i2cpframerate) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpexpo) < 0) - goto err; - if (i2c_w(gspca_dev, i2cpdoit) < 0) - goto err; + i2c_w(gspca_dev, i2cpframerate); + i2c_w(gspca_dev, i2cpexpo); + i2c_w(gspca_dev, i2cpdoit); + break; + } + default: break; - } } - return; -err: - PDEBUG(D_ERR, "i2c error exposure"); } static void setfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - switch (sd->sensor) { - case SENSOR_OV6650: - case SENSOR_OV7630: { + if (sd->sensor == SENSOR_OV6650 || sd->sensor == SENSOR_OV7630) { /* Framerate adjust register for artificial light 50 hz flicker compensation, for the ov6650 this is identical to ov6630 0x2b register, see ov6630 datasheet. 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */ __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}; - switch (sd->ctrls[FREQ].val) { + switch (sd->plfreq->val) { default: /* case 0: * no filter*/ /* case 2: * 60 hz */ @@ -993,25 +876,17 @@ static void setfreq(struct gspca_dev *gspca_dev) break; } i2c[1] = sensor_data[sd->sensor].sensor_addr; - if (i2c_w(gspca_dev, i2c) < 0) - PDEBUG(D_ERR, "i2c error setfreq"); - break; - } + i2c_w(gspca_dev, i2c); } } -#define WANT_REGULAR_AUTOGAIN -#define WANT_COARSE_EXPO_AUTOGAIN -#include "autogain_functions.h" - static void do_autogain(struct gspca_dev *gspca_dev) { - int deadzone, desired_avg_lum, result; struct sd *sd = (struct sd *) gspca_dev; - int avg_lum = atomic_read(&sd->avg_lum); + int deadzone, desired_avg_lum, avg_lum; - if ((gspca_dev->ctrl_dis & (1 << AUTOGAIN)) || - avg_lum == -1 || !sd->ctrls[AUTOGAIN].val) + avg_lum = atomic_read(&sd->avg_lum); + if (avg_lum == -1) return; if (sd->autogain_ignore_frames > 0) { @@ -1030,22 +905,18 @@ static void do_autogain(struct gspca_dev *gspca_dev) desired_avg_lum = 13000; } - if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) - result = coarse_grained_expo_autogain(gspca_dev, avg_lum, - sd->ctrls[BRIGHTNESS].val - * desired_avg_lum / 127, - deadzone); - else - result = auto_gain_n_exposure(gspca_dev, avg_lum, - sd->ctrls[BRIGHTNESS].val - * desired_avg_lum / 127, - deadzone, GAIN_KNEE, EXPOSURE_KNEE); - - if (result) { - PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d", - (int) sd->ctrls[GAIN].val, - (int) sd->ctrls[EXPOSURE].val); - sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; + if (sd->brightness) + desired_avg_lum = sd->brightness->val * desired_avg_lum / 127; + + if (gspca_dev->exposure->maximum < 500) { + if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum, + desired_avg_lum, deadzone)) + sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; + } else { + int gain_knee = gspca_dev->gain->maximum * 9 / 10; + if (gspca_expo_autogain(gspca_dev, avg_lum, desired_avg_lum, + deadzone, gain_knee, sd->exposure_knee)) + sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; } } @@ -1064,14 +935,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor = id->driver_info >> 8; sd->bridge = id->driver_info & 0xff; - gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis; -#if AUTOGAIN_DEF - if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN))) - gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); -#endif - cam = &gspca_dev->cam; - cam->ctrls = sd->ctrls; if (!(sensor_data[sd->sensor].flags & F_SIF)) { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); @@ -1087,18 +951,143 @@ static int sd_config(struct gspca_dev *gspca_dev, /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; const __u8 stop = 0x09; /* Disable stream turn of LED */ - if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { - sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN; - sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX; - sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF; - if (sd->ctrls[EXPOSURE].val > COARSE_EXPOSURE_MAX) - sd->ctrls[EXPOSURE].val = COARSE_EXPOSURE_DEF; + reg_w(gspca_dev, 0x01, &stop, 1); + + return gspca_dev->usb_err; +} + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) { + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + gspca_dev->gain->val = gspca_dev->gain->default_value; + gspca_dev->exposure->val = gspca_dev->exposure->default_value; + sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; } - reg_w(gspca_dev, 0x01, &stop, 1); + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev); + break; + case V4L2_CID_AUTOGAIN: + if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val)) + setexposure(gspca_dev); + if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val)) + setgain(gspca_dev); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + setfreq(gspca_dev); + break; + default: + return -EINVAL; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +/* this function is called at probe time */ +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 5); + + if (sd->sensor == SENSOR_OV6650 || sd->sensor == SENSOR_OV7630 || + sd->sensor == SENSOR_PAS106 || sd->sensor == SENSOR_PAS202) + sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); + + /* Gain range is sensor dependent */ + switch (sd->sensor) { + case SENSOR_OV6650: + case SENSOR_PAS106: + case SENSOR_PAS202: + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 31, 1, 15); + break; + case SENSOR_OV7630: + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 47, 1, 31); + break; + case SENSOR_HV7131D: + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 63, 1, 31); + break; + case SENSOR_TAS5110C: + case SENSOR_TAS5110D: + case SENSOR_TAS5130CXX: + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 255, 1, 127); + break; + default: + if (sd->bridge == BRIDGE_103) { + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 127, 1, 63); + } else { + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 15, 1, 7); + } + } + + /* Exposure range is sensor dependent, and not all have exposure */ + switch (sd->sensor) { + case SENSOR_HV7131D: + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 8191, 1, 482); + sd->exposure_knee = 964; + break; + case SENSOR_OV6650: + case SENSOR_OV7630: + case SENSOR_PAS106: + case SENSOR_PAS202: + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 1023, 1, 66); + sd->exposure_knee = 200; + break; + case SENSOR_TAS5110C: + case SENSOR_TAS5110D: + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 2, 15, 1, 2); + break; + } + + if (gspca_dev->exposure) { + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + } + + if (sd->sensor == SENSOR_OV6650 || sd->sensor == SENSOR_OV7630) + sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, + V4L2_CID_POWER_LINE_FREQUENCY_DISABLED); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + if (gspca_dev->autogain) + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); return 0; } @@ -1242,10 +1231,10 @@ static int sd_start(struct gspca_dev *gspca_dev) sd->frames_to_drop = 0; sd->autogain_ignore_frames = 0; - sd->exp_too_high_cnt = 0; - sd->exp_too_low_cnt = 0; + gspca_dev->exp_too_high_cnt = 0; + gspca_dev->exp_too_low_cnt = 0; atomic_set(&sd->avg_lum, -1); - return 0; + return gspca_dev->usb_err; } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -1387,37 +1376,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AUTOGAIN].val = val; - sd->exp_too_high_cnt = 0; - sd->exp_too_low_cnt = 0; - - /* when switching to autogain set defaults to make sure - we are on a valid point of the autogain gain / - exposure knee graph, and give this change time to - take effect before doing autogain. */ - if (sd->ctrls[AUTOGAIN].val - && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) { - sd->ctrls[EXPOSURE].val = sd->ctrls[EXPOSURE].def; - sd->ctrls[GAIN].val = sd->ctrls[GAIN].def; - if (gspca_dev->streaming) { - sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; - setexposure(gspca_dev); - setgain(gspca_dev); - } - } - - if (sd->ctrls[AUTOGAIN].val) - gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); - else - gspca_dev->ctrl_inac = 0; - - return 0; -} - static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { @@ -1461,10 +1419,9 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, @@ -1529,6 +1486,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index f38faa9b37c3..150b2df40f7f 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -3199,6 +3199,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c index 070b9c33b517..14d635277d71 100644 --- a/drivers/media/video/gspca/spca1528.c +++ b/drivers/media/video/gspca/spca1528.c @@ -33,102 +33,11 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - u8 brightness; - u8 contrast; - u8 hue; - u8 color; - u8 sharpness; - u8 pkt_seq; u8 jpeg_hdr[JPEG_HDR_SZ]; }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 128 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 8, - .step = 1, -#define CONTRAST_DEF 1 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 255, - .step = 1, -#define HUE_DEF 0 - .default_value = HUE_DEF, - }, - .set = sd_sethue, - .get = sd_gethue, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 8, - .step = 1, -#define COLOR_DEF 1 - .default_value = COLOR_DEF, - }, - .set = sd_setcolor, - .get = sd_getcolor, - }, - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define SHARPNESS_DEF 0 - .default_value = SHARPNESS_DEF, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { /* (does not work correctly) {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -259,58 +168,40 @@ static void wait_status_1(struct gspca_dev *gspca_dev) gspca_dev->usb_err = -ETIME; } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, sd->brightness); + reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, val); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, sd->contrast); + reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, val); } -static void sethue(struct gspca_dev *gspca_dev) +static void sethue(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, sd->hue); + reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, val); } -static void setcolor(struct gspca_dev *gspca_dev) +static void setcolor(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, sd->color); + reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, val); } -static void setsharpness(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, sd->sharpness); + reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, val); } /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; - gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */ /*fixme: 256 in ms-win traces*/ - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->hue = HUE_DEF; - sd->color = COLOR_DEF; - sd->sharpness = SHARPNESS_DEF; - return 0; } @@ -370,14 +261,6 @@ static int sd_start(struct gspca_dev *gspca_dev) /* the JPEG quality shall be 85% */ jpeg_set_qual(sd->jpeg_hdr, 85); - /* set the controls */ - setbrightness(gspca_dev); - setcontrast(gspca_dev); - sethue(gspca_dev); - setcolor(gspca_dev); - setsharpness(gspca_dev); - - msleep(5); reg_r(gspca_dev, 0x00, 0x2520, 1); msleep(8); @@ -457,103 +340,70 @@ err: gspca_dev->last_packet_type = DISCARD_PACKET; } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) - sethue(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hue; - return 0; -} - -static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->color = val; - if (gspca_dev->streaming) - setcolor(gspca_dev); + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_HUE: + sethue(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolor(gspca_dev, ctrl->val); + break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + } return gspca_dev->usb_err; } -static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->color; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return gspca_dev->usb_err; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 5); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 8, 1, 1); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HUE, 0, 255, 1, 0); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 8, 1, 1); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 255, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, @@ -587,6 +437,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 103984708c77..25cb68d0556d 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -30,18 +30,12 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver"); MODULE_LICENSE("GPL"); +#define QUALITY 85 + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - u8 quality; -#define QUALITY_MIN 70 -#define QUALITY_MAX 95 -#define QUALITY_DEF 85 - char subtype; #define AgfaCl20 0 #define AiptekPocketDV 1 @@ -62,59 +56,6 @@ struct sd { u8 jpeg_hdr[JPEG_HDR_SZ]; }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 127 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 63, - .step = 1, -#define CONTRAST_DEF 31 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 63, - .step = 1, -#define COLOR_DEF 31 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, @@ -641,10 +582,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); } - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->quality = QUALITY_DEF; return 0; } @@ -673,7 +610,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + jpeg_set_qual(sd->jpeg_hdr, QUALITY); if (sd->subtype == LogitechClickSmart310) { xmult = 0x16; @@ -934,122 +871,79 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - reg_w(gspca_dev, 0x00, 0x8167, - (__u8) (sd->brightness - 128)); + (__u8) (val - 128)); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0x00, 0x8168, sd->contrast); + reg_w(gspca_dev, 0x00, 0x8168, val); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_w(gspca_dev, 0x00, 0x8169, sd->colors); + reg_w(gspca_dev, 0x00, 0x8169, val); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} + gspca_dev->usb_err = 0; -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return 0; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 3); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 63, 1, 31); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 63, 1, 31); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, }; /* -- module initialisation -- */ @@ -1089,6 +983,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c index 9c16821addd4..3b7f777785b4 100644 --- a/drivers/media/video/gspca/spca501.c +++ b/drivers/media/video/gspca/spca501.c @@ -49,91 +49,6 @@ struct sd { #define ViewQuestM318B 6 }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define MY_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define MY_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 64725, - .step = 1, - .default_value = 64725, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define MY_COLOR 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 20, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -#define MY_BLUE_BALANCE 3 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 0, - }, - .set = sd_setblue_balance, - .get = sd_getblue_balance, - }, -#define MY_RED_BALANCE 4 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 0, - }, - .set = sd_setred_balance, - .get = sd_getred_balance, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, .bytesperline = 160, @@ -1878,42 +1793,32 @@ static int write_vector(struct gspca_dev *gspca_dev, return 0; } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness); + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, val); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - reg_write(gspca_dev->dev, 0x00, 0x00, - (sd->contrast >> 8) & 0xff); + (val >> 8) & 0xff); reg_write(gspca_dev->dev, 0x00, 0x01, - sd->contrast & 0xff); + val & 0xff); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, sd->colors); + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, val); } -static void setblue_balance(struct gspca_dev *gspca_dev) +static void setblue_balance(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->blue_balance); + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, val); } -static void setred_balance(struct gspca_dev *gspca_dev) +static void setred_balance(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->red_balance); + reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, val); } /* this function is called at probe time */ @@ -1927,9 +1832,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); sd->subtype = id->driver_info; - sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value; - sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value; return 0; } @@ -2008,13 +1910,6 @@ static int sd_start(struct gspca_dev *gspca_dev) } reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02); - /* HDG atleast the Intel CreateAndShare needs to have one of its - * brightness / contrast / color set otherwise it assumes what seems - * max contrast. Note that strange enough setting any of these is - * enough to fix the max contrast problem, to be sure we set all 3 */ - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); return 0; } @@ -2053,103 +1948,70 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + gspca_dev->usb_err = 0; - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->blue_balance = val; - if (gspca_dev->streaming) - setblue_balance(gspca_dev); - return 0; -} - -static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->blue_balance; - return 0; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_BLUE_BALANCE: + setblue_balance(gspca_dev, ctrl->val); + break; + case V4L2_CID_RED_BALANCE: + setred_balance(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } -static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->red_balance = val; - if (gspca_dev->streaming) - setred_balance(gspca_dev); - return 0; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->red_balance; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 5); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 127, 1, 0); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 64725, 1, 64725); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 63, 1, 20); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 127, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, @@ -2185,6 +2047,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c index 1320f35e39f2..bc7d67c3cb04 100644 --- a/drivers/media/video/gspca/spca505.c +++ b/drivers/media/video/gspca/spca505.c @@ -33,34 +33,11 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - u8 brightness; - u8 subtype; #define IntelPCCameraPro 0 #define Nxultra 1 }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 127 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, .bytesperline = 160, @@ -633,7 +610,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_mode); else /* no 640x480 for IntelPCCameraPro */ cam->nmodes = ARRAY_SIZE(vga_mode) - 1; - sd->brightness = BRIGHTNESS_DEF; return 0; } @@ -651,11 +627,8 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness) { - struct sd *sd = (struct sd *) gspca_dev; - u8 brightness = sd->brightness; - reg_write(gspca_dev->dev, 0x05, 0x00, (255 - brightness) >> 6); reg_write(gspca_dev->dev, 0x05, 0x01, (255 - brightness) << 2); } @@ -706,13 +679,9 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_write(dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]); reg_write(dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]); - ret = reg_write(dev, SPCA50X_REG_USB, + return reg_write(dev, SPCA50X_REG_USB, SPCA50X_USB_CTRL, SPCA50X_CUSB_ENABLE); - - setbrightness(gspca_dev); - - return ret; } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -756,30 +725,49 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; - *val = sd->brightness; + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 5); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, + .init_controls = sd_init_controls, .init = sd_init, .start = sd_start, .stopN = sd_stopN, @@ -812,6 +800,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index 54eed87672d2..969bb5a4cd93 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c @@ -33,83 +33,10 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned char brightness; - unsigned char contrast; - unsigned char colors; - unsigned char hue; char norme; char channel; }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x80, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x47, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SD_COLOR 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x40, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -#define SD_HUE 3 - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0, - }, - .set = sd_sethue, - .get = sd_gethue, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, .bytesperline = 160, @@ -281,16 +208,11 @@ static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code, static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; cam = &gspca_dev->cam; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; - sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; - sd->hue = sd_ctrls[SD_HUE].qctrl.default_value; return 0; } @@ -564,121 +486,93 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, sd->brightness, SAA7113_bright); + spca506_WriteI2c(gspca_dev, val, SAA7113_bright); spca506_WriteI2c(gspca_dev, 0x01, 0x09); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, sd->contrast, SAA7113_contrast); + spca506_WriteI2c(gspca_dev, val, SAA7113_contrast); spca506_WriteI2c(gspca_dev, 0x01, 0x09); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, sd->colors, SAA7113_saturation); + spca506_WriteI2c(gspca_dev, val, SAA7113_saturation); spca506_WriteI2c(gspca_dev, 0x01, 0x09); } -static void sethue(struct gspca_dev *gspca_dev) +static void sethue(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - spca506_Initi2c(gspca_dev); - spca506_WriteI2c(gspca_dev, sd->hue, SAA7113_hue); + spca506_WriteI2c(gspca_dev, val, SAA7113_hue); spca506_WriteI2c(gspca_dev, 0x01, 0x09); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} + gspca_dev->usb_err = 0; -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_HUE: + sethue(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) - sethue(gspca_dev); - return 0; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hue; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 0x47); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 0x40); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HUE, 0, 255, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, @@ -711,6 +605,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index df4e16996461..1286b4170b88 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -32,8 +32,6 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - u8 brightness; - u8 subtype; #define CreativeVista 0 #define HamaUSBSightcam 1 @@ -43,27 +41,6 @@ struct sd { #define ViewQuestVQ110 5 }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 128 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -}; - static const struct v4l2_pix_format sif_mode[] = { {160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, .bytesperline = 160, @@ -1411,7 +1388,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(sif_mode); sd->subtype = id->driver_info; - sd->brightness = BRIGHTNESS_DEF; init_data = init_data_tb[sd->subtype]; return write_vector(gspca_dev, init_data); @@ -1471,11 +1447,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness) { - struct sd *sd = (struct sd *) gspca_dev; - u8 brightness = sd->brightness; - /* MX seem contrast */ reg_write(gspca_dev->dev, 0x8651, brightness); reg_write(gspca_dev->dev, 0x8652, brightness); @@ -1483,31 +1456,50 @@ static void setbrightness(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, 0x8654, brightness); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; - *val = sd->brightness; + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 5); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, @@ -1541,6 +1533,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index 4a5f209ce719..cfe71dd6747d 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -31,39 +31,17 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver"); MODULE_LICENSE("GPL"); +#define EXPOSURE_MAX (2047 + 325) + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - __u16 exposure; /* rev12a only */ -#define EXPOSURE_MIN 1 -#define EXPOSURE_DEF 700 /* == 10 fps */ -#define EXPOSURE_MAX (2047 + 325) /* see setexposure */ - - __u8 contrast; /* rev72a only */ -#define CONTRAST_MIN 0x00 -#define CONTRAST_DEF 0x20 -#define CONTRAST_MAX 0x3f - - __u8 brightness; /* rev72a only */ -#define BRIGHTNESS_MIN 0 -#define BRIGHTNESS_DEF 0x20 -#define BRIGHTNESS_MAX 0x3f - - __u8 white; -#define HUE_MIN 1 -#define HUE_DEF 0x40 -#define HUE_MAX 0x7f - - __u8 autogain; -#define AUTOGAIN_MIN 0 -#define AUTOGAIN_DEF 1 -#define AUTOGAIN_MAX 1 - - __u8 gain; /* rev12a only */ -#define GAIN_MIN 0 -#define GAIN_DEF 63 -#define GAIN_MAX 255 + struct { /* hue/contrast control cluster */ + struct v4l2_ctrl *contrast; + struct v4l2_ctrl *hue; + }; + struct v4l2_ctrl *autogain; #define EXPO12A_DEF 3 __u8 expo12a; /* expo/gain? for rev 12a */ @@ -461,12 +439,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = sif_072a_mode; cam->nmodes = ARRAY_SIZE(sif_072a_mode); } - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->white = HUE_DEF; - sd->exposure = EXPOSURE_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->gain = GAIN_DEF; sd->expo12a = EXPO12A_DEF; return 0; } @@ -491,66 +463,49 @@ static int sd_init_72a(struct gspca_dev *gspca_dev) return 0; } -/* rev 72a only */ -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; - __u8 value; + __u16 reg; - value = sd->brightness; + if (sd->chip_revision == Rev012A) + reg = 0x8610; + else + reg = 0x8611; - /* offsets for white balance */ - reg_w_val(dev, 0x8611, value); /* R */ - reg_w_val(dev, 0x8612, value); /* Gr */ - reg_w_val(dev, 0x8613, value); /* B */ - reg_w_val(dev, 0x8614, value); /* Gb */ + reg_w_val(dev, reg + 0, val); /* R */ + reg_w_val(dev, reg + 1, val); /* Gr */ + reg_w_val(dev, reg + 2, val); /* B */ + reg_w_val(dev, reg + 3, val); /* Gb */ } -static void setwhite(struct gspca_dev *gspca_dev) +static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast) { struct sd *sd = (struct sd *) gspca_dev; - __u16 white; + struct usb_device *dev = gspca_dev->dev; __u8 blue, red; __u16 reg; /* try to emulate MS-win as possible */ - white = sd->white; red = 0x20 + white * 3 / 8; blue = 0x90 - white * 5 / 8; if (sd->chip_revision == Rev012A) { reg = 0x8614; } else { reg = 0x8651; - red += sd->contrast - 0x20; - blue += sd->contrast - 0x20; + red += contrast - 0x20; + blue += contrast - 0x20; + reg_w_val(dev, 0x8652, contrast + 0x20); /* Gr */ + reg_w_val(dev, 0x8654, contrast + 0x20); /* Gb */ } - reg_w_val(gspca_dev->dev, reg, red); - reg_w_val(gspca_dev->dev, reg + 2, blue); -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - __u8 value; - - if (sd->chip_revision != Rev072A) - return; - value = sd->contrast + 0x20; - - /* gains for white balance */ - setwhite(gspca_dev); -/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */ - reg_w_val(dev, 0x8652, value); /* Gr */ -/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */ - reg_w_val(dev, 0x8654, value); /* Gb */ + reg_w_val(dev, reg, red); + reg_w_val(dev, reg + 2, blue); } /* rev 12a only */ -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; int i, expo = 0; /* Register 0x8309 controls exposure for the spca561, @@ -572,8 +527,8 @@ static void setexposure(struct gspca_dev *gspca_dev) int table[] = { 0, 450, 550, 625, EXPOSURE_MAX }; for (i = 0; i < ARRAY_SIZE(table) - 1; i++) { - if (sd->exposure <= table[i + 1]) { - expo = sd->exposure - table[i]; + if (val <= table[i + 1]) { + expo = val - table[i]; if (i) expo += 300; expo |= i << 11; @@ -587,29 +542,27 @@ static void setexposure(struct gspca_dev *gspca_dev) } /* rev 12a only */ -static void setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the sensitivity when set, so 31 + one of them set == 63, and 15 with both of them set == 63 */ - if (sd->gain < 64) - gspca_dev->usb_buf[0] = sd->gain; - else if (sd->gain < 128) - gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40; + if (val < 64) + gspca_dev->usb_buf[0] = val; + else if (val < 128) + gspca_dev->usb_buf[0] = (val / 2) | 0x40; else - gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xc0; + gspca_dev->usb_buf[0] = (val / 4) | 0xc0; gspca_dev->usb_buf[1] = 0; reg_w_buf(gspca_dev, 0x8335, 2); } -static void setautogain(struct gspca_dev *gspca_dev) +static void setautogain(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->autogain) + if (val) sd->ag_cnt = AG_CNT_START; else sd->ag_cnt = -1; @@ -644,9 +597,6 @@ static int sd_start_12a(struct gspca_dev *gspca_dev) memcpy(gspca_dev->usb_buf, Reg8391, 8); reg_w_buf(gspca_dev, 0x8391, 8); reg_w_buf(gspca_dev, 0x8390, 8); - setwhite(gspca_dev); - setgain(gspca_dev); - setexposure(gspca_dev); /* Led ON (bit 3 -> 0 */ reg_w_val(gspca_dev->dev, 0x8114, 0x00); @@ -654,6 +604,7 @@ static int sd_start_12a(struct gspca_dev *gspca_dev) } static int sd_start_72a(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; int Clck; int mode; @@ -683,9 +634,10 @@ static int sd_start_72a(struct gspca_dev *gspca_dev) reg_w_val(dev, 0x8702, 0x81); reg_w_val(dev, 0x8500, mode); /* mode */ write_sensor_72a(gspca_dev, rev72a_init_sensor2); - setcontrast(gspca_dev); + setwhite(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue), + v4l2_ctrl_g_ctrl(sd->contrast)); /* setbrightness(gspca_dev); * fixme: bad values */ - setautogain(gspca_dev); + setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain)); reg_w_val(dev, 0x8112, 0x10 | 0x20); return 0; } @@ -819,221 +771,96 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -/* rev 72a only */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -/* rev 72a only */ -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; + gspca_dev->usb_err = 0; - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - sd->autogain = val; - if (gspca_dev->streaming) - setautogain(gspca_dev); - return 0; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->white = val; - if (gspca_dev->streaming) - setwhite(gspca_dev); - return 0; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + /* hue/contrast control cluster for 72a */ + setwhite(gspca_dev, sd->hue->val, ctrl->val); + break; + case V4L2_CID_HUE: + /* just plain hue control for 12a */ + setwhite(gspca_dev, ctrl->val, 0); + break; + case V4L2_CID_EXPOSURE: + setexposure(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + setgain(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + setautogain(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } -static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->white; - return 0; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -/* rev12a only */ -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +static int sd_init_controls_12a(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 3); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HUE, 1, 0x7f, 1, 0x40); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 1, EXPOSURE_MAX, 1, 700); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 255, 1, 63); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } -/* rev12a only */ -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +static int sd_init_controls_72a(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 0x3f, 1, 0x20); + sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HUE, 1, 0x7f, 1, 0x40); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 0x3f, 1, 0x20); + sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - *val = sd->gain; + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + v4l2_ctrl_cluster(2, &sd->contrast); return 0; } -/* control tables */ -static const struct ctrl sd_ctrls_12a[] = { - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = HUE_MIN, - .maximum = HUE_MAX, - .step = 1, - .default_value = HUE_DEF, - }, - .set = sd_setwhite, - .get = sd_getwhite, - }, - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = EXPOSURE_MIN, - .maximum = EXPOSURE_MAX, - .step = 1, - .default_value = EXPOSURE_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = GAIN_MIN, - .maximum = GAIN_MAX, - .step = 1, - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - -static const struct ctrl sd_ctrls_72a[] = { - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = HUE_MIN, - .maximum = HUE_MAX, - .step = 1, - .default_value = HUE_DEF, - }, - .set = sd_setwhite, - .get = sd_getwhite, - }, - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = BRIGHTNESS_MIN, - .maximum = BRIGHTNESS_MAX, - .step = 1, - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = CONTRAST_MIN, - .maximum = CONTRAST_MAX, - .step = 1, - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = AUTOGAIN_MIN, - .maximum = AUTOGAIN_MAX, - .step = 1, - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - /* sub-driver description */ static const struct sd_desc sd_desc_12a = { .name = MODULE_NAME, - .ctrls = sd_ctrls_12a, - .nctrls = ARRAY_SIZE(sd_ctrls_12a), + .init_controls = sd_init_controls_12a, .config = sd_config, .init = sd_init_12a, .start = sd_start_12a, @@ -1045,8 +872,7 @@ static const struct sd_desc sd_desc_12a = { }; static const struct sd_desc sd_desc_72a = { .name = MODULE_NAME, - .ctrls = sd_ctrls_72a, - .nctrls = ARRAY_SIZE(sd_ctrls_72a), + .init_controls = sd_init_controls_72a, .config = sd_config, .init = sd_init_72a, .start = sd_start_72a, @@ -1103,6 +929,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c index 04f54654a026..a8ac97931ad6 100644 --- a/drivers/media/video/gspca/sq905.c +++ b/drivers/media/video/gspca/sq905.c @@ -433,6 +433,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c index f34ddb0570c8..2c2f3d2f357f 100644 --- a/drivers/media/video/gspca/sq905c.c +++ b/drivers/media/video/gspca/sq905c.c @@ -340,6 +340,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c index 1a8ba9b3550a..3e1e486af883 100644 --- a/drivers/media/video/gspca/sq930x.c +++ b/drivers/media/video/gspca/sq930x.c @@ -36,8 +36,10 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - u16 expo; - u8 gain; + struct { /* exposure/gain control cluster */ + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + }; u8 do_ctrl; u8 gpio[2]; @@ -55,42 +57,6 @@ enum sensors { SENSOR_OV9630, }; -static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0x0001, - .maximum = 0x0fff, - .step = 1, -#define EXPO_DEF 0x0356 - .default_value = EXPO_DEF, - }, - .set = sd_setexpo, - .get = sd_getexpo, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0x01, - .maximum = 0xff, - .step = 1, -#define GAIN_DEF 0x8d - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - static struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, .bytesperline = 320, @@ -791,7 +757,7 @@ static void lz24bp_ppl(struct sd *sd, u16 ppl) ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2); } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 gain) { struct sd *sd = (struct sd *) gspca_dev; int i, integclks, intstartclk, frameclks, min_frclk; @@ -799,7 +765,7 @@ static void setexposure(struct gspca_dev *gspca_dev) u16 cmd; u8 buf[15]; - integclks = sd->expo; + integclks = expo; i = 0; cmd = SQ930_CTRL_SET_EXPOSURE; @@ -818,7 +784,7 @@ static void setexposure(struct gspca_dev *gspca_dev) buf[i++] = intstartclk; buf[i++] = frameclks >> 8; buf[i++] = frameclks; - buf[i++] = sd->gain; + buf[i++] = gain; break; default: /* cmos */ /* case SENSOR_MI0360: */ @@ -834,7 +800,7 @@ static void setexposure(struct gspca_dev *gspca_dev) buf[i++] = 0x35; /* reg = global gain */ buf[i++] = 0x00; /* val H */ buf[i++] = sensor->i2c_dum; - buf[i++] = 0x80 + sd->gain / 2; /* val L */ + buf[i++] = 0x80 + gain / 2; /* val L */ buf[i++] = 0x00; buf[i++] = 0x00; buf[i++] = 0x00; @@ -860,9 +826,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->bulk = 1; - sd->gain = GAIN_DEF; - sd->expo = EXPO_DEF; - return 0; } @@ -1089,7 +1052,8 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev) return; sd->do_ctrl = 0; - setexposure(gspca_dev); + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure), + v4l2_ctrl_g_ctrl(sd->gain)); gspca_dev->cam.bulk_nurbs = 1; ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC); @@ -1113,48 +1077,55 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); } -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); struct sd *sd = (struct sd *) gspca_dev; - sd->gain = val; - if (gspca_dev->streaming) - sd->do_ctrl = 1; - return 0; -} + gspca_dev->usb_err = 0; -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - *val = sd->gain; - return 0; + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + setexposure(gspca_dev, ctrl->val, sd->gain->val); + break; + } + return gspca_dev->usb_err; } -static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - sd->expo = val; - if (gspca_dev->streaming) - sd->do_ctrl = 1; - return 0; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; struct sd *sd = (struct sd *) gspca_dev; - *val = sd->expo; + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 2); + sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 0xfff, 1, 0x356); + sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 1, 255, 1, 0x8d); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + v4l2_ctrl_cluster(2, &sd->exposure); return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, @@ -1194,6 +1165,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 4ae7cc8f463a..8c0982607f25 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -29,86 +29,14 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver"); MODULE_LICENSE("GPL"); -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - COLORS, - LIGHTFREQ, - NCTRLS /* number of controls */ -}; +#define QUALITY 50 /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; - - u8 quality; -#define QUALITY_MIN 70 -#define QUALITY_MAX 95 -#define QUALITY_DEF 88 - u8 jpeg_hdr[JPEG_HDR_SZ]; }; -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void setlightfreq(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setbrightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setcontrast - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 127, - }, - .set_control = setcolors - }, -[LIGHTFREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 1, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, - .default_value = 1, - }, - .set_control = setlightfreq - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, @@ -255,41 +183,36 @@ static void set_par(struct gspca_dev *gspca_dev, snd_val(gspca_dev, 0x003f08, parval); } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; int parval; parval = 0x06000000 /* whiteness */ - + (sd->ctrls[BRIGHTNESS].val << 16); + + (val << 16); set_par(gspca_dev, parval); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; int parval; parval = 0x07000000 /* contrast */ - + (sd->ctrls[CONTRAST].val << 16); + + (val << 16); set_par(gspca_dev, parval); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; int parval; parval = 0x08000000 /* saturation */ - + (sd->ctrls[COLORS].val << 16); + + (val << 16); set_par(gspca_dev, parval); } -static void setlightfreq(struct gspca_dev *gspca_dev) +static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - set_par(gspca_dev, sd->ctrls[LIGHTFREQ].val == 1 + set_par(gspca_dev, val == 1 ? 0x33640000 /* 50 Hz */ : 0x33780000); /* 60 Hz */ } @@ -298,12 +221,8 @@ static void setlightfreq(struct gspca_dev *gspca_dev) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; - gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); - gspca_dev->cam.ctrls = sd->ctrls; - sd->quality = QUALITY_DEF; return 0; } @@ -333,7 +252,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + jpeg_set_qual(sd->jpeg_hdr, QUALITY); /* work on alternate 1 */ usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); @@ -365,14 +284,10 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x0640, 0); reg_w(gspca_dev, 0x0650, 0); reg_w(gspca_dev, 0x0660, 0); - setbrightness(gspca_dev); /* whiteness */ - setcontrast(gspca_dev); /* contrast */ - setcolors(gspca_dev); /* saturation */ set_par(gspca_dev, 0x09800000); /* Red ? */ set_par(gspca_dev, 0x0a800000); /* Green ? */ set_par(gspca_dev, 0x0b800000); /* Blue ? */ set_par(gspca_dev, 0x0d030000); /* Gamma ? */ - setlightfreq(gspca_dev); /* start the video flow */ set_par(gspca_dev, 0x01000000); @@ -435,62 +350,70 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm)) - break; - strcpy((char *) menu->name, freq_nm[menu->index]); - return 0; - } - return -EINVAL; -} + gspca_dev->usb_err = 0; -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + setlightfreq(gspca_dev, ctrl->val); + break; + } return gspca_dev->usb_err; } -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 127); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 127); + v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, }; /* -- module initialisation -- */ @@ -516,6 +439,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/video/gspca/stv0680.c index 461ed645f309..67605272aaa8 100644 --- a/drivers/media/video/gspca/stv0680.c +++ b/drivers/media/video/gspca/stv0680.c @@ -46,10 +46,6 @@ struct sd { u8 current_mode; }; -/* V4L2 controls supported by the driver */ -static const struct ctrl sd_ctrls[] = { -}; - static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val, int size) { @@ -318,8 +314,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, .start = sd_start, @@ -352,6 +346,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index c80f0c0c75b6..9ccfcb1c6479 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -30,18 +30,13 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver"); MODULE_LICENSE("GPL"); +#define QUALITY 85 + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - s8 brightness; - u8 contrast; - u8 colors; - u8 autogain; - u8 quality; -#define QUALITY_MIN 70 -#define QUALITY_MAX 95 -#define QUALITY_DEF 85 + bool autogain; u8 bridge; #define BRIDGE_SPCA504 0 @@ -59,75 +54,6 @@ struct sd { u8 jpeg_hdr[JPEG_HDR_SZ]; }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = -128, - .maximum = 127, - .step = 1, -#define BRIGHTNESS_DEF 0 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, -#define CONTRAST_DEF 0x20 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 0xff, - .step = 1, -#define COLOR_DEF 0x1a - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, @@ -597,31 +523,31 @@ static void spca504B_setQtable(struct gspca_dev *gspca_dev) spca504B_PollingDataReady(gspca_dev); } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; u16 reg; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; - reg_w_riv(gspca_dev, 0x00, reg, sd->brightness); + reg_w_riv(gspca_dev, 0x00, reg, val); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; u16 reg; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; - reg_w_riv(gspca_dev, 0x00, reg, sd->contrast); + reg_w_riv(gspca_dev, 0x00, reg, val); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; u16 reg; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; - reg_w_riv(gspca_dev, 0x00, reg, sd->colors); + reg_w_riv(gspca_dev, 0x00, reg, val); } static void init_ctl_reg(struct gspca_dev *gspca_dev) @@ -629,10 +555,6 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int pollreg = 1; - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); - switch (sd->bridge) { case BRIDGE_SPCA504: case BRIDGE_SPCA504C: @@ -704,11 +626,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_mode2); break; } - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->quality = QUALITY_DEF; return 0; } @@ -807,7 +724,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x22); /* JPEG 411 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + jpeg_set_qual(sd->jpeg_hdr, QUALITY); if (sd->bridge == BRIDGE_SPCA504B) spca504B_setQtable(gspca_dev); @@ -1012,116 +929,69 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} + gspca_dev->usb_err = 0; -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + sd->autogain = ctrl->val; + break; + } return gspca_dev->usb_err; } -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - return 0; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return gspca_dev->usb_err; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_get_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; - jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT - | V4L2_JPEG_MARKER_DQT; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 0x20); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 0x1a); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, }; /* -- module initialisation -- */ @@ -1208,6 +1078,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index 9b9f85a8e60e..8bc6c3ceec2c 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -34,28 +34,19 @@ #include <linux/slab.h> #include "gspca.h" -#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0) - MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>"); MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver"); MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - - u8 brightness; - u8 contrast; - u8 colors; - u8 autogain; - u8 gamma; - u8 sharpness; - u8 freq; - u8 red_gain; - u8 blue_gain; - u8 green_gain; - u8 awb; /* set default r/g/b and activate */ - u8 mirror; - u8 effect; + struct v4l2_ctrl *freq; + struct { /* awb / color gains control cluster */ + struct v4l2_ctrl *awb; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *red_balance; + struct v4l2_ctrl *blue_balance; + }; u8 sensor; u8 button_pressed; @@ -67,245 +58,31 @@ enum sensors { SENSOR_LT168G, /* must verify if this is the actual model */ }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); - -static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); - -static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val); -static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 14, - .step = 1, -#define BRIGHTNESS_DEF 8 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0x0d, - .step = 1, -#define CONTRAST_DEF 0x07 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 0, - .maximum = 0x0f, - .step = 1, -#define COLORS_DEF 0x05 - .default_value = COLORS_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -#define GAMMA_MAX 16 -#define GAMMA_DEF 10 - { - { - .id = V4L2_CID_GAMMA, /* (gamma on win) */ - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = GAMMA_MAX - 1, - .step = 1, - .default_value = GAMMA_DEF, - }, - .set = sd_setgamma, - .get = sd_getgamma, - }, - { - { - .id = V4L2_CID_BACKLIGHT_COMPENSATION, /* Activa lowlight, - * some apps dont bring up the - * backligth_compensation control) */ - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Low Light", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 0x01 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setlowlight, - .get = sd_getlowlight, - }, - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror Image", - .minimum = 0, - .maximum = 1, - .step = 1, -#define MIRROR_DEF 0 - .default_value = MIRROR_DEF, - }, - .set = sd_setmirror, - .get = sd_getmirror - }, - { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light Frequency Filter", - .minimum = 1, /* 1 -> 0x50, 2->0x60 */ - .maximum = 2, - .step = 1, -#define FREQ_DEF 1 - .default_value = FREQ_DEF, - }, - .set = sd_setfreq, - .get = sd_getfreq}, - - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Auto White Balance", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AWB_DEF 0 - .default_value = AWB_DEF, - }, - .set = sd_setawb, - .get = sd_getawb - }, - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 15, - .step = 1, -#define SHARPNESS_DEF 0x06 - .default_value = SHARPNESS_DEF, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, - { - { - .id = V4L2_CID_EFFECTS, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Webcam Effects", - .minimum = 0, - .maximum = 4, - .step = 1, -#define EFFECTS_DEF 0 - .default_value = EFFECTS_DEF, - }, - .set = sd_seteffect, - .get = sd_geteffect - }, - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 0x10, - .maximum = 0x40, - .step = 1, -#define BLUE_GAIN_DEF 0x20 - .default_value = BLUE_GAIN_DEF, - }, - .set = sd_setblue_gain, - .get = sd_getblue_gain, - }, - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 0x10, - .maximum = 0x40, - .step = 1, -#define RED_GAIN_DEF 0x20 - .default_value = RED_GAIN_DEF, - }, - .set = sd_setred_gain, - .get = sd_getred_gain, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0x10, - .maximum = 0x40, - .step = 1, -#define GAIN_DEF 0x20 - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - static const struct v4l2_pix_format vga_mode_t16[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 4}, +#if 0 /* HDG: broken with my test cam, so lets disable it */ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 3}, +#endif {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 2}, +#if 0 /* HDG: broken with my test cam, so lets disable it */ {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 352, .sizeimage = 352 * 288 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, +#endif {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 640, .sizeimage = 640 * 480 * 3 / 8 + 590, @@ -454,17 +231,6 @@ static const struct additional_sensor_data sensor_data[] = { }; #define MAX_EFFECTS 7 -/* easily done by soft, this table could be removed, - * i keep it here just in case */ -static char *effects_control[MAX_EFFECTS] = { - "Normal", - "Emboss", /* disabled */ - "Monochrome", - "Sepia", - "Sketch", - "Sun Effect", /* disabled */ - "Negative", -}; static const u8 effects_table[MAX_EFFECTS][6] = { {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */ {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */ @@ -475,7 +241,8 @@ static const u8 effects_table[MAX_EFFECTS][6] = { {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40}, /* Negative */ }; -static const u8 gamma_table[GAMMA_MAX][17] = { +#define GAMMA_MAX (15) +static const u8 gamma_table[GAMMA_MAX+1][17] = { /* gamma table from cam1690.ini */ {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */ 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb, @@ -683,38 +450,18 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - - cam = &gspca_dev->cam; + struct cam *cam = &gspca_dev->cam; cam->cam_mode = vga_mode_t16; cam->nmodes = ARRAY_SIZE(vga_mode_t16); - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLORS_DEF; - sd->gamma = GAMMA_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->mirror = MIRROR_DEF; - sd->freq = FREQ_DEF; - sd->awb = AWB_DEF; - sd->sharpness = SHARPNESS_DEF; - sd->effect = EFFECTS_DEF; - sd->red_gain = RED_GAIN_DEF; - sd->blue_gain = BLUE_GAIN_DEF; - sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF; - return 0; } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness) { - struct sd *sd = (struct sd *) gspca_dev; - unsigned int brightness; u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 }; - brightness = sd->brightness; if (brightness < 7) { set6[1] = 0x26; set6[3] = 0x70 - brightness * 0x10; @@ -725,10 +472,8 @@ static void setbrightness(struct gspca_dev *gspca_dev) reg_w_buf(gspca_dev, set6, sizeof set6); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 contrast) { - struct sd *sd = (struct sd *) gspca_dev; - unsigned int contrast = sd->contrast; u16 reg_to_write; if (contrast < 7) @@ -739,89 +484,62 @@ static void setcontrast(struct gspca_dev *gspca_dev) reg_w(gspca_dev, reg_to_write); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u16 reg_to_write; - reg_to_write = 0x80bb + sd->colors * 0x100; /* was 0xc0 */ + reg_to_write = 0x80bb + val * 0x100; /* was 0xc0 */ reg_w(gspca_dev, reg_to_write); } -static void setgamma(struct gspca_dev *gspca_dev) +static void setgamma(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_CONF, "Gamma: %d", sd->gamma); reg_w_ixbuf(gspca_dev, 0x90, - gamma_table[sd->gamma], sizeof gamma_table[0]); + gamma_table[val], sizeof gamma_table[0]); } -static void setRGB(struct gspca_dev *gspca_dev) +static void setawb_n_RGB(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - u8 all_gain_reg[6] = - {0x87, 0x00, 0x88, 0x00, 0x89, 0x00}; + u8 all_gain_reg[8] = { + 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00 }; + s32 red_gain, blue_gain, green_gain; + + green_gain = sd->gain->val; + + red_gain = green_gain + sd->red_balance->val; + if (red_gain > 0x40) + red_gain = 0x40; + else if (red_gain < 0x10) + red_gain = 0x10; + + blue_gain = green_gain + sd->blue_balance->val; + if (blue_gain > 0x40) + blue_gain = 0x40; + else if (blue_gain < 0x10) + blue_gain = 0x10; + + all_gain_reg[1] = red_gain; + all_gain_reg[3] = blue_gain; + all_gain_reg[5] = green_gain; + all_gain_reg[7] = sensor_data[sd->sensor].reg80; + if (!sd->awb->val) + all_gain_reg[7] &= ~0x04; /* AWB off */ - all_gain_reg[1] = sd->red_gain; - all_gain_reg[3] = sd->blue_gain; - all_gain_reg[5] = sd->green_gain; reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); } -/* Generic fnc for r/b balance, exposure and awb */ -static void setawb(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - u16 reg80; - - reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80; - - /* on awb leave defaults values */ - if (!sd->awb) { - /* shoud we wait here.. */ - /* update and reset RGB gains with webcam values */ - sd->red_gain = reg_r(gspca_dev, 0x0087); - sd->blue_gain = reg_r(gspca_dev, 0x0088); - sd->green_gain = reg_r(gspca_dev, 0x0089); - reg80 &= ~0x0400; /* AWB off */ - } - reg_w(gspca_dev, reg80); - reg_w(gspca_dev, reg80); -} - -static void init_gains(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 reg80; - u8 all_gain_reg[8] = - {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00}; - - all_gain_reg[1] = sd->red_gain; - all_gain_reg[3] = sd->blue_gain; - all_gain_reg[5] = sd->green_gain; - reg80 = sensor_data[sd->sensor].reg80; - if (!sd->awb) - reg80 &= ~0x04; - all_gain_reg[7] = reg80; - reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg); - - reg_w(gspca_dev, (sd->red_gain << 8) + 0x87); - reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88); - reg_w(gspca_dev, (sd->green_gain << 8) + 0x89); -} - -static void setsharpness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; u16 reg_to_write; - reg_to_write = 0x0aa6 + 0x1000 * sd->sharpness; + reg_to_write = 0x0aa6 + 0x1000 * val; reg_w(gspca_dev, reg_to_write); } -static void setfreq(struct gspca_dev *gspca_dev) +static void setfreq(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; u8 reg66; @@ -829,7 +547,7 @@ static void setfreq(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_LT168G: - if (sd->freq != 0) + if (val != 0) freq[3] = 0xa8; reg66 = 0x41; break; @@ -840,7 +558,7 @@ static void setfreq(struct gspca_dev *gspca_dev) reg66 = 0x40; break; } - switch (sd->freq) { + switch (val) { case 0: /* no flicker */ freq[3] = 0xf0; break; @@ -941,14 +659,9 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80); reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80); reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e); - - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setgamma(gspca_dev); - setcolors(gspca_dev); - setsharpness(gspca_dev); - init_gains(gspca_dev); - setfreq(gspca_dev); + reg_w(gspca_dev, (0x20 << 8) + 0x87); + reg_w(gspca_dev, (0x20 << 8) + 0x88); + reg_w(gspca_dev, (0x20 << 8) + 0x89); reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5); reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8); @@ -968,31 +681,44 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void setmirror(struct gspca_dev *gspca_dev) +static void setmirror(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 hflipcmd[8] = {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09}; - if (sd->mirror) + if (val) hflipcmd[3] = 0x01; reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd); } -static void seteffect(struct gspca_dev *gspca_dev) +static void seteffect(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; + int idx = 0; - reg_w_buf(gspca_dev, effects_table[sd->effect], - sizeof effects_table[0]); - if (sd->effect == 1 || sd->effect == 5) { - PDEBUG(D_CONF, - "This effect have been disabled for webcam \"safety\""); - return; + switch (val) { + case V4L2_COLORFX_NONE: + break; + case V4L2_COLORFX_BW: + idx = 2; + break; + case V4L2_COLORFX_SEPIA: + idx = 3; + break; + case V4L2_COLORFX_SKETCH: + idx = 4; + break; + case V4L2_COLORFX_NEGATIVE: + idx = 6; + break; + default: + break; } - if (sd->effect == 1 || sd->effect == 4) + reg_w_buf(gspca_dev, effects_table[idx], + sizeof effects_table[0]); + + if (val == V4L2_COLORFX_SKETCH) reg_w(gspca_dev, 0x4aa6); else reg_w(gspca_dev, 0xfaa6); @@ -1070,7 +796,7 @@ static int sd_start(struct gspca_dev *gspca_dev) break; } sensor = &sensor_data[sd->sensor]; - setfreq(gspca_dev); + setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq)); reg_r(gspca_dev, 0x0012); reg_w_buf(gspca_dev, t2, sizeof t2); reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3); @@ -1142,296 +868,157 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, pkt_type, data, len); } -static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->blue_gain = val; - if (gspca_dev->streaming) - reg_w(gspca_dev, (val << 8) + 0x88); - return 0; -} - -static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->blue_gain; - return 0; -} - -static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->red_gain = val; - if (gspca_dev->streaming) - reg_w(gspca_dev, (val << 8) + 0x87); - - return 0; -} - -static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->red_gain; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - u16 psg, nsg; - - psg = sd->red_gain + sd->blue_gain + sd->green_gain; - nsg = val * 3; - sd->red_gain = sd->red_gain * nsg / psg; - if (sd->red_gain > 0x40) - sd->red_gain = 0x40; - else if (sd->red_gain < 0x10) - sd->red_gain = 0x10; - sd->blue_gain = sd->blue_gain * nsg / psg; - if (sd->blue_gain > 0x40) - sd->blue_gain = 0x40; - else if (sd->blue_gain < 0x10) - sd->blue_gain = 0x10; - sd->green_gain = sd->green_gain * nsg / psg; - if (sd->green_gain > 0x40) - sd->green_gain = 0x40; - else if (sd->green_gain < 0x10) - sd->green_gain = 0x10; - - if (gspca_dev->streaming) - setRGB(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3; - return 0; -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return *val; -} - -static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->awb = val; - if (gspca_dev->streaming) - setawb(gspca_dev); - return 0; -} - -static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->awb; - return *val; -} - -static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->mirror = val; - if (gspca_dev->streaming) - setmirror(gspca_dev); - return 0; -} - -static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->mirror; - return *val; -} - -static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->effect = val; - if (gspca_dev->streaming) - seteffect(gspca_dev); - return 0; -} - -static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->effect; - return *val; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return *val; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return 0; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gamma = val; - if (gspca_dev->streaming) - setgamma(gspca_dev); - return 0; -} - -static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gamma; - return 0; -} - -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) +static int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; - - sd->freq = val; - if (gspca_dev->streaming) - setfreq(gspca_dev); + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + s32 red_gain, blue_gain, green_gain; + + gspca_dev->usb_err = 0; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + red_gain = reg_r(gspca_dev, 0x0087); + if (red_gain > 0x40) + red_gain = 0x40; + else if (red_gain < 0x10) + red_gain = 0x10; + + blue_gain = reg_r(gspca_dev, 0x0088); + if (blue_gain > 0x40) + blue_gain = 0x40; + else if (blue_gain < 0x10) + blue_gain = 0x10; + + green_gain = reg_r(gspca_dev, 0x0089); + if (green_gain > 0x40) + green_gain = 0x40; + else if (green_gain < 0x10) + green_gain = 0x10; + + sd->gain->val = green_gain; + sd->red_balance->val = red_gain - green_gain; + sd->blue_balance->val = blue_gain - green_gain; + break; + } return 0; } -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - *val = sd->freq; - return 0; -} + gspca_dev->usb_err = 0; -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return 0; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAMMA: + setgamma(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + setmirror(gspca_dev, ctrl->val); + break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + setfreq(gspca_dev, ctrl->val); + break; + case V4L2_CID_BACKLIGHT_COMPENSATION: + reg_w(gspca_dev, ctrl->val ? 0xf48e : 0xb48e); + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + setawb_n_RGB(gspca_dev); + break; + case V4L2_CID_COLORFX: + seteffect(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .g_volatile_ctrl = sd_g_volatile_ctrl, + .s_ctrl = sd_s_ctrl, +}; -/* Low Light set here......*/ -static int sd_setlowlight(struct gspca_dev *gspca_dev, __s32 val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 12); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 14, 1, 8); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 0x0d, 1, 7); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 0xf, 1, 5); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 10); + /* Activate lowlight, some apps dont bring up the + backlight_compensation control) */ + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BACKLIGHT_COMPENSATION, 0, 1, 1, 1); + if (sd->sensor == SENSOR_TAS5130A) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sd->awb = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0x10, 0x40, 1, 0x20); + sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, 0); + sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, 0); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 15, 1, 6); + v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_COLORFX, V4L2_COLORFX_SKETCH, + ~((1 << V4L2_COLORFX_NONE) | + (1 << V4L2_COLORFX_BW) | + (1 << V4L2_COLORFX_SEPIA) | + (1 << V4L2_COLORFX_SKETCH) | + (1 << V4L2_COLORFX_NEGATIVE)), + V4L2_COLORFX_NONE); + sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } - sd->autogain = val; - if (val != 0) - reg_w(gspca_dev, 0xf48e); - else - reg_w(gspca_dev, 0xb48e); - return 0; -} + v4l2_ctrl_auto_cluster(4, &sd->awb, 0, true); -static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; return 0; } -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; - - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm)) - break; - strcpy((char *) menu->name, freq_nm[menu->index]); - return 0; - case V4L2_CID_EFFECTS: - if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) { - strlcpy((char *) menu->name, - effects_control[menu->index], - sizeof menu->name); - return 0; - } - break; - } - return -EINVAL; -} - /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) .other_input = 1, #endif @@ -1460,6 +1047,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c index c6326d177a3d..a6055246cb9d 100644 --- a/drivers/media/video/gspca/topro.c +++ b/drivers/media/video/gspca/topro.c @@ -120,24 +120,13 @@ static const u8 jpeg_head[] = { #define JPEG_HDR_SZ 521 }; -enum e_ctrl { - EXPOSURE, - QUALITY, - SHARPNESS, - RGAIN, - GAIN, - BGAIN, - GAMMA, - AUTOGAIN, - NCTRLS /* number of controls */ -}; - -#define AUTOGAIN_DEF 1 - struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct gspca_ctrl ctrls[NCTRLS]; + struct v4l2_ctrl *jpegqual; + struct v4l2_ctrl *sharpness; + struct v4l2_ctrl *gamma; + struct v4l2_ctrl *blue; + struct v4l2_ctrl *red; u8 framerate; u8 quality; /* webcam current JPEG quality (0..16) */ @@ -1415,32 +1404,33 @@ static void soi763a_6810_init(struct gspca_dev *gspca_dev) } /* set the gain and exposure */ -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 gain, + s32 blue, s32 red) { struct sd *sd = (struct sd *) gspca_dev; if (sd->sensor == SENSOR_CX0342) { - int expo; - - expo = (sd->ctrls[EXPOSURE].val << 2) - 1; + expo = (expo << 2) - 1; i2c_w(gspca_dev, CX0342_EXPO_LINE_L, expo); i2c_w(gspca_dev, CX0342_EXPO_LINE_H, expo >> 8); if (sd->bridge == BRIDGE_TP6800) i2c_w(gspca_dev, CX0342_RAW_GBGAIN_H, - sd->ctrls[GAIN].val >> 8); - i2c_w(gspca_dev, CX0342_RAW_GBGAIN_L, sd->ctrls[GAIN].val); + gain >> 8); + i2c_w(gspca_dev, CX0342_RAW_GBGAIN_L, gain); if (sd->bridge == BRIDGE_TP6800) i2c_w(gspca_dev, CX0342_RAW_GRGAIN_H, - sd->ctrls[GAIN].val >> 8); - i2c_w(gspca_dev, CX0342_RAW_GRGAIN_L, sd->ctrls[GAIN].val); - if (sd->bridge == BRIDGE_TP6800) - i2c_w(gspca_dev, CX0342_RAW_BGAIN_H, - sd->ctrls[BGAIN].val >> 8); - i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, sd->ctrls[BGAIN].val); - if (sd->bridge == BRIDGE_TP6800) - i2c_w(gspca_dev, CX0342_RAW_RGAIN_H, - sd->ctrls[RGAIN].val >> 8); - i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, sd->ctrls[RGAIN].val); + gain >> 8); + i2c_w(gspca_dev, CX0342_RAW_GRGAIN_L, gain); + if (sd->sensor == SENSOR_CX0342) { + if (sd->bridge == BRIDGE_TP6800) + i2c_w(gspca_dev, CX0342_RAW_BGAIN_H, + blue >> 8); + i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, blue); + if (sd->bridge == BRIDGE_TP6800) + i2c_w(gspca_dev, CX0342_RAW_RGAIN_H, + red >> 8); + i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, red); + } i2c_w(gspca_dev, CX0342_SYS_CTRL_0, sd->bridge == BRIDGE_TP6800 ? 0x80 : 0x81); return; @@ -1448,10 +1438,10 @@ static void setexposure(struct gspca_dev *gspca_dev) /* soi763a */ i2c_w(gspca_dev, 0x10, /* AEC_H (exposure time) */ - sd->ctrls[EXPOSURE].val); + expo); /* i2c_w(gspca_dev, 0x76, 0x02); * AEC_L ([1:0] */ i2c_w(gspca_dev, 0x00, /* gain */ - sd->ctrls[GAIN].val); + gain); } /* set the JPEG quantization tables */ @@ -1472,12 +1462,10 @@ static void set_dqt(struct gspca_dev *gspca_dev, u8 q) } /* set the JPEG compression quality factor */ -static void setquality(struct gspca_dev *gspca_dev) +static void setquality(struct gspca_dev *gspca_dev, s32 q) { struct sd *sd = (struct sd *) gspca_dev; - u16 q; - q = sd->ctrls[QUALITY].val; if (q != 16) q = 15 - q; @@ -1508,10 +1496,9 @@ static const u8 color_gain[NSENSORS][18] = { 0xd5, 0x00, 0x46, 0x03, 0xdc, 0x03}, /* V R/G/B */ }; -static void setgamma(struct gspca_dev *gspca_dev) +static void setgamma(struct gspca_dev *gspca_dev, s32 gamma) { struct sd *sd = (struct sd *) gspca_dev; - int gamma; #define NGAMMA 6 static const u8 gamma_tb[NGAMMA][3][1024] = { { /* gamma 0 - from tp6800 + soi763a */ @@ -3836,7 +3823,6 @@ static void setgamma(struct gspca_dev *gspca_dev) if (sd->bridge == BRIDGE_TP6810) reg_w(gspca_dev, 0x02, 0x28); /* msleep(50); */ - gamma = sd->ctrls[GAMMA].val; bulk_w(gspca_dev, 0x00, gamma_tb[gamma][0], 1024); bulk_w(gspca_dev, 0x01, gamma_tb[gamma][1], 1024); bulk_w(gspca_dev, 0x02, gamma_tb[gamma][2], 1024); @@ -3864,43 +3850,35 @@ static void setgamma(struct gspca_dev *gspca_dev) /* msleep(50); */ } -static void setsharpness(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - u8 val; if (sd->bridge == BRIDGE_TP6800) { - val = sd->ctrls[SHARPNESS].val - | 0x08; /* grid compensation enable */ + val |= 0x08; /* grid compensation enable */ if (gspca_dev->width == 640) reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */ else val |= 0x04; /* scaling down enable */ reg_w(gspca_dev, TP6800_R5D_DEMOSAIC_CFG, val); } else { - val = (sd->ctrls[SHARPNESS].val << 5) | 0x08; + val = (val << 5) | 0x08; reg_w(gspca_dev, 0x59, val); } } -static void setautogain(struct gspca_dev *gspca_dev) +static void setautogain(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) - return; - if (sd->ctrls[AUTOGAIN].val) { - sd->ag_cnt = AG_CNT_START; - gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); - } else { - sd->ag_cnt = -1; - gspca_dev->ctrl_inac &= ~((1 << EXPOSURE) | (1 << GAIN)); - } + sd->ag_cnt = val ? AG_CNT_START : -1; } /* set the resolution for sensor cx0342 */ static void set_resolution(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00); if (gspca_dev->width == 320) { reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x06); @@ -3926,8 +3904,9 @@ static void set_resolution(struct gspca_dev *gspca_dev) i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x01); bulk_w(gspca_dev, 0x03, color_gain[SENSOR_CX0342], ARRAY_SIZE(color_gain[0])); - setgamma(gspca_dev); - setquality(gspca_dev); + setgamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma)); + if (sd->sensor == SENSOR_SOI763A) + setquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual)); } /* convert the frame rate to a tp68x0 value */ @@ -3963,7 +3942,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev) return i; } -static void setframerate(struct gspca_dev *gspca_dev) +static void setframerate(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; u8 fr_idx; @@ -3974,7 +3953,7 @@ static void setframerate(struct gspca_dev *gspca_dev) reg_r(gspca_dev, 0x7b); reg_w(gspca_dev, 0x7b, sd->sensor == SENSOR_CX0342 ? 0x10 : 0x90); - if (sd->ctrls[EXPOSURE].val >= 128) + if (val >= 128) fr_idx = 0xf0; /* lower frame rate */ } @@ -3984,43 +3963,43 @@ static void setframerate(struct gspca_dev *gspca_dev) i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01); } -static void setrgain(struct gspca_dev *gspca_dev) +static void setrgain(struct gspca_dev *gspca_dev, s32 rgain) { - struct sd *sd = (struct sd *) gspca_dev; - int rgain; - - rgain = sd->ctrls[RGAIN].val; i2c_w(gspca_dev, CX0342_RAW_RGAIN_H, rgain >> 8); i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, rgain); i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x80); } -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +static int sd_setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + s32 val = gspca_dev->gain->val; if (sd->sensor == SENSOR_CX0342) { - sd->ctrls[BGAIN].val = sd->ctrls[BGAIN].val - * val / sd->ctrls[GAIN].val; - if (sd->ctrls[BGAIN].val > 4095) - sd->ctrls[BGAIN].val = 4095; - sd->ctrls[RGAIN].val = sd->ctrls[RGAIN].val - * val / sd->ctrls[GAIN].val; - if (sd->ctrls[RGAIN].val > 4095) - sd->ctrls[RGAIN].val = 4095; + s32 old = gspca_dev->gain->cur.val ? + gspca_dev->gain->cur.val : 1; + + sd->blue->val = sd->blue->val * val / old; + if (sd->blue->val > 4095) + sd->blue->val = 4095; + sd->red->val = sd->red->val * val / old; + if (sd->red->val > 4095) + sd->red->val = 4095; + } + if (gspca_dev->streaming) { + if (sd->sensor == SENSOR_CX0342) + setexposure(gspca_dev, gspca_dev->exposure->val, + gspca_dev->gain->val, + sd->blue->val, sd->red->val); + else + setexposure(gspca_dev, gspca_dev->exposure->val, + gspca_dev->gain->val, 0, 0); } - sd->ctrls[GAIN].val = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); return gspca_dev->usb_err; } -static void setbgain(struct gspca_dev *gspca_dev) +static void setbgain(struct gspca_dev *gspca_dev, s32 bgain) { - struct sd *sd = (struct sd *) gspca_dev; - int bgain; - - bgain = sd->ctrls[BGAIN].val; i2c_w(gspca_dev, CX0342_RAW_BGAIN_H, bgain >> 8); i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, bgain); i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x80); @@ -4040,7 +4019,6 @@ static int sd_config(struct gspca_dev *gspca_dev, framerates : framerates_6810; sd->framerate = 30; /* default: 30 fps */ - gspca_dev->cam.ctrls = sd->ctrls; return 0; } @@ -4108,32 +4086,16 @@ static int sd_init(struct gspca_dev *gspca_dev) } if (sd->sensor == SENSOR_SOI763A) { pr_info("Sensor soi763a\n"); - sd->ctrls[GAMMA].def = sd->bridge == BRIDGE_TP6800 ? 0 : 1; - sd->ctrls[GAIN].max = 15; - sd->ctrls[GAIN].def = 3; - gspca_dev->ctrl_dis = (1 << RGAIN) | (1 << BGAIN); if (sd->bridge == BRIDGE_TP6810) { soi763a_6810_init(gspca_dev); -#if AUTOGAIN_DEF - gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); -#endif - } else { - gspca_dev->ctrl_dis |= (1 << AUTOGAIN); } } else { pr_info("Sensor cx0342\n"); if (sd->bridge == BRIDGE_TP6810) { cx0342_6810_init(gspca_dev); -#if AUTOGAIN_DEF - gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); -#endif - } else { - gspca_dev->ctrl_dis |= (1 << AUTOGAIN); } } - if (sd->bridge == BRIDGE_TP6810) - sd->ctrls[QUALITY].def = 0; /* auto quality */ set_dqt(gspca_dev, 0); return 0; } @@ -4207,8 +4169,9 @@ static void set_led(struct gspca_dev *gspca_dev, int on) static void cx0342_6800_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; static const struct cmd reg_init[] = { -/*fixme: is this usefull?*/ + /* fixme: is this useful? */ {TP6800_R17_GPIO_IO, 0x9f}, {TP6800_R16_GPIO_PD, 0x40}, {TP6800_R10_SIF_TYPE, 0x00}, /* i2c 8 bits */ @@ -4279,13 +4242,21 @@ static void cx0342_6800_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, TP6800_R54_DARK_CFG, 0x00); i2c_w(gspca_dev, CX0342_EXPO_LINE_H, 0x00); i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x01); - setexposure(gspca_dev); + if (sd->sensor == SENSOR_CX0342) + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), + v4l2_ctrl_g_ctrl(sd->blue), + v4l2_ctrl_g_ctrl(sd->red)); + else + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0); set_led(gspca_dev, 1); set_resolution(gspca_dev); } static void cx0342_6810_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; static const struct cmd sensor_init_2[] = { {CX0342_EXPO_LINE_L, 0x6f}, {CX0342_EXPO_LINE_H, 0x02}, @@ -4366,10 +4337,10 @@ static void cx0342_6810_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x07, 0x85); reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01); /* qvga */ } - setgamma(gspca_dev); + setgamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma)); reg_w_buf(gspca_dev, tp6810_bridge_start, ARRAY_SIZE(tp6810_bridge_start)); - setsharpness(gspca_dev); + setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness)); bulk_w(gspca_dev, 0x03, color_gain[SENSOR_CX0342], ARRAY_SIZE(color_gain[0])); reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x87); @@ -4380,11 +4351,12 @@ static void cx0342_6810_start(struct gspca_dev *gspca_dev) i2c_w_buf(gspca_dev, sensor_init_5, ARRAY_SIZE(sensor_init_5)); set_led(gspca_dev, 1); -/* setquality(gspca_dev); */ +/* setquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual)); */ } static void soi763a_6800_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; static const struct cmd reg_init[] = { {TP6800_R79_QUALITY, 0x04}, {TP6800_R79_QUALITY, 0x01}, @@ -4484,19 +4456,28 @@ static void soi763a_6800_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, TP6800_R5C_EDGE_THRLD, 0x10); reg_w(gspca_dev, TP6800_R54_DARK_CFG, 0x00); - setsharpness(gspca_dev); + setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness)); bulk_w(gspca_dev, 0x03, color_gain[SENSOR_SOI763A], ARRAY_SIZE(color_gain[0])); set_led(gspca_dev, 1); - setexposure(gspca_dev); - setquality(gspca_dev); - setgamma(gspca_dev); + if (sd->sensor == SENSOR_CX0342) + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), + v4l2_ctrl_g_ctrl(sd->blue), + v4l2_ctrl_g_ctrl(sd->red)); + else + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0); + if (sd->sensor == SENSOR_SOI763A) + setquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual)); + setgamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma)); } static void soi763a_6810_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; static const struct cmd bridge_init_2[] = { {TP6800_R7A_BLK_THRLD, 0x00}, {TP6800_R79_QUALITY, 0x04}, @@ -4520,7 +4501,14 @@ static void soi763a_6810_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x22, gspca_dev->alt); bulk_w(gspca_dev, 0x03, color_null, sizeof color_null); reg_w(gspca_dev, 0x59, 0x40); - setexposure(gspca_dev); + if (sd->sensor == SENSOR_CX0342) + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), + v4l2_ctrl_g_ctrl(sd->blue), + v4l2_ctrl_g_ctrl(sd->red)); + else + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0); reg_w_buf(gspca_dev, bridge_init_2, ARRAY_SIZE(bridge_init_2)); reg_w_buf(gspca_dev, tp6810_ov_init_common, ARRAY_SIZE(tp6810_ov_init_common)); @@ -4534,7 +4522,7 @@ static void soi763a_6810_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x07, 0x85); reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01); /* qvga */ } - setgamma(gspca_dev); + setgamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma)); reg_w_buf(gspca_dev, tp6810_bridge_start, ARRAY_SIZE(tp6810_bridge_start)); @@ -4545,12 +4533,19 @@ static void soi763a_6810_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x00, 0x00); - setsharpness(gspca_dev); + setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness)); bulk_w(gspca_dev, 0x03, color_gain[SENSOR_SOI763A], ARRAY_SIZE(color_gain[0])); set_led(gspca_dev, 1); reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0xf0); - setexposure(gspca_dev); + if (sd->sensor == SENSOR_CX0342) + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), + v4l2_ctrl_g_ctrl(sd->blue), + v4l2_ctrl_g_ctrl(sd->red)); + else + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0); reg_w_buf(gspca_dev, bridge_init_6, ARRAY_SIZE(bridge_init_6)); } @@ -4576,12 +4571,25 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x80, 0x03); reg_w(gspca_dev, 0x82, gspca_dev->curr_mode ? 0x0a : 0x0e); - setexposure(gspca_dev); - setquality(gspca_dev); - setautogain(gspca_dev); + if (sd->sensor == SENSOR_CX0342) + setexposure(gspca_dev, + v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), + v4l2_ctrl_g_ctrl(sd->blue), + v4l2_ctrl_g_ctrl(sd->red)); + else + setexposure(gspca_dev, + v4l2_ctrl_g_ctrl(gspca_dev->exposure), + v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0); + if (sd->sensor == SENSOR_SOI763A) + setquality(gspca_dev, + v4l2_ctrl_g_ctrl(sd->jpegqual)); + if (sd->bridge == BRIDGE_TP6810) + setautogain(gspca_dev, + v4l2_ctrl_g_ctrl(gspca_dev->autogain)); } - setframerate(gspca_dev); + setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure)); return gspca_dev->usb_err; } @@ -4672,12 +4680,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -/* -- do autogain -- */ -/* gain setting is done in setexposure() for tp6810 */ -static void setgain(struct gspca_dev *gspca_dev) {} -#define WANT_REGULAR_AUTOGAIN -#include "autogain_functions.h" - static void sd_dq_callback(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -4739,17 +4741,19 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev) luma /= 4; reg_w(gspca_dev, 0x7d, 0x00); - expo = sd->ctrls[EXPOSURE].val; - ret = auto_gain_n_exposure(gspca_dev, luma, + expo = v4l2_ctrl_g_ctrl(gspca_dev->exposure); + ret = gspca_expo_autogain(gspca_dev, luma, 60, /* desired luma */ 6, /* dead zone */ 2, /* gain knee */ 70); /* expo knee */ sd->ag_cnt = AG_CNT_START; if (sd->bridge == BRIDGE_TP6810) { - if ((expo >= 128 && sd->ctrls[EXPOSURE].val < 128) - || (expo < 128 && sd->ctrls[EXPOSURE].val >= 128)) - setframerate(gspca_dev); + int new_expo = v4l2_ctrl_g_ctrl(gspca_dev->exposure); + + if ((expo >= 128 && new_expo < 128) + || (expo < 128 && new_expo >= 128)) + setframerate(gspca_dev, new_expo); } break; } @@ -4789,7 +4793,7 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev, sd->framerate = tpf->denominator / tpf->numerator; if (gspca_dev->streaming) - setframerate(gspca_dev); + setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure)); /* Return the actual framerate */ i = get_fr_idx(gspca_dev); @@ -4806,12 +4810,10 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; - if (sd->sensor == SENSOR_SOI763A) - jpeg_set_qual(sd->jpeg_hdr, jcomp->quality); -/* else - fixme: TODO -*/ - return gspca_dev->usb_err; + if (sd->sensor != SENSOR_SOI763A) + return -ENOTTY; + v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality); + return 0; } static int sd_get_jcomp(struct gspca_dev *gspca_dev, @@ -4819,118 +4821,109 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; + if (sd->sensor != SENSOR_SOI763A) + return -ENOTTY; memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = jpeg_q[sd->quality]; + jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT; return 0; } -static struct ctrl sd_ctrls[NCTRLS] = { -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0x01, - .maximum = 0xdc, - .step = 1, - .default_value = 0x4e, - }, - .set_control = setexposure - }, -[QUALITY] = { - { - .id = V4L2_CID_PRIVATE_BASE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Compression quality", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 13, - }, - .set_control = setquality - }, -[RGAIN] = { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red balance", - .minimum = 0, - .maximum = 4095, - .step = 1, - .default_value = 256, - }, - .set_control = setrgain - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 4095, - .step = 1, - .default_value = 256, - }, - .set = sd_setgain - }, -[BGAIN] = { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue balance", - .minimum = 0, - .maximum = 4095, - .step = 1, - .default_value = 256, - }, - .set_control = setbgain - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 2, - }, - .set_control = setsharpness - }, -[GAMMA] = { - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = NGAMMA - 1, - .step = 1, - .default_value = 1, - }, - .set_control = setgamma - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = AUTOGAIN_DEF - }, - .set_control = setautogain - }, +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAMMA: + setgamma(gspca_dev, ctrl->val); + break; + case V4L2_CID_BLUE_BALANCE: + setbgain(gspca_dev, ctrl->val); + break; + case V4L2_CID_RED_BALANCE: + setrgain(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + sd_setgain(gspca_dev); + break; + case V4L2_CID_AUTOGAIN: + if (ctrl->val) + break; + sd_setgain(gspca_dev); + break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + jpeg_set_qual(sd->jpeg_hdr, ctrl->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, }; +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 1, 0xdc, 1, 0x4e); + if (sd->sensor == SENSOR_CX0342) { + sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 4095, 1, 256); + sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 4095, 1, 256); + } + if (sd->sensor == SENSOR_SOI763A) + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 15, 1, 3); + else + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 4095, 1, 256); + sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 3, 1, 2); + sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAMMA, 0, NGAMMA - 1, 1, + (sd->sensor == SENSOR_SOI763A && + sd->bridge == BRIDGE_TP6800) ? 0 : 1); + if (sd->bridge == BRIDGE_TP6810) + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + if (sd->sensor == SENSOR_SOI763A) + sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, + 0, 15, 1, (sd->bridge == BRIDGE_TP6810) ? 0 : 13); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + if (gspca_dev->autogain) + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); + else + v4l2_ctrl_cluster(2, &gspca_dev->exposure); + return 0; +} + static const struct sd_desc sd_desc = { .name = KBUILD_MODNAME, - .ctrls = sd_ctrls, - .nctrls = NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c index c8922c5ffbf5..8591324a53e1 100644 --- a/drivers/media/video/gspca/tv8532.c +++ b/drivers/media/video/gspca/tv8532.c @@ -30,49 +30,9 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - __u16 exposure; - __u16 gain; - __u8 packet; }; -/* V4L2 controls supported by the driver */ -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 0x18f, - .step = 1, -#define EXPOSURE_DEF 0x18f - .default_value = EXPOSURE_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 0x7ff, - .step = 1, -#define GAIN_DEF 0x100 - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - static const struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 176, @@ -202,15 +162,12 @@ static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; cam = &gspca_dev->cam; cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); - sd->exposure = EXPOSURE_DEF; - sd->gain = GAIN_DEF; return 0; } @@ -241,23 +198,19 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->exposure); + reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, val); reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE); /* 0x84 */ } -static void setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_w2(gspca_dev, R20_GAIN_G1L, sd->gain); - reg_w2(gspca_dev, R22_GAIN_RL, sd->gain); - reg_w2(gspca_dev, R24_GAIN_BL, sd->gain); - reg_w2(gspca_dev, R26_GAIN_G2L, sd->gain); + reg_w2(gspca_dev, R20_GAIN_G1L, val); + reg_w2(gspca_dev, R22_GAIN_RL, val); + reg_w2(gspca_dev, R24_GAIN_BL, val); + reg_w2(gspca_dev, R26_GAIN_G2L, val); } /* -- start the camera -- */ @@ -289,9 +242,6 @@ static int sd_start(struct gspca_dev *gspca_dev) tv_8532_setReg(gspca_dev); - setexposure(gspca_dev); - setgain(gspca_dev); - /************************************************/ reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */ msleep(200); @@ -339,49 +289,55 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data + gspca_dev->width + 5, gspca_dev->width); } -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} + gspca_dev->usb_err = 0; -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + if (!gspca_dev->streaming) + return 0; - *val = sd->exposure; - return 0; + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + setexposure(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + setgain(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; } -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 2); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 0x18f, 1, 0x18f); + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 0x7ff, 1, 0x100); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, @@ -415,6 +371,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 208f6b2d512a..f21fd1677c38 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -33,18 +33,10 @@ MODULE_LICENSE("GPL"); /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - - u8 brightness; - u8 contrast; - u8 colors; - u8 hflip; - u8 vflip; - u8 lightfreq; - s8 sharpness; - u16 exposure; - u8 gain; - u8 autogain; - u8 backlight; + struct { /* hvflip cluster */ + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + }; u8 image_offset; @@ -73,252 +65,6 @@ enum sensors { NSENSORS }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setbacklight(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbacklight(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define BRIGHTNESS_IDX 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, -#define BRIGHTNESS_DEF 128 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define CONTRAST_IDX 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define COLORS_IDX 2 - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 1, - .maximum = 127, - .step = 1, -#define COLOR_DEF 63 - .default_value = COLOR_DEF, - }, - .set = sd_setcolors, - .get = sd_getcolors, - }, -/* next 2 controls work with some sensors only */ -#define HFLIP_IDX 3 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, -#define HFLIP_DEF 0 - .default_value = HFLIP_DEF, - }, - .set = sd_sethflip, - .get = sd_gethflip, - }, -#define VFLIP_IDX 4 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, -#define VFLIP_DEF 0 - .default_value = VFLIP_DEF, - }, - .set = sd_setvflip, - .get = sd_getvflip, - }, -#define LIGHTFREQ_IDX 5 - { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: No, 1: 50Hz, 2:60Hz */ - .step = 1, -#define FREQ_DEF 1 - .default_value = FREQ_DEF, - }, - .set = sd_setfreq, - .get = sd_getfreq, - }, -#define SHARPNESS_IDX 6 - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = -1, - .maximum = 2, - .step = 1, -#define SHARPNESS_DEF -1 - .default_value = SHARPNESS_DEF, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, -#define GAIN_IDX 7 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 78, - .step = 1, -#define GAIN_DEF 0 - .default_value = GAIN_DEF, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -#define EXPOSURE_IDX 8 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", -#define EXPOSURE_DEF 450 - .minimum = 0, - .maximum = 4095, - .step = 1, - .default_value = EXPOSURE_DEF, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, -#define AUTOGAIN_IDX 9 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain and Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -#define BACKLIGHT_IDX 10 - { - { - .id = V4L2_CID_BACKLIGHT_COMPENSATION, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Backlight Compensation", - .minimum = 0, - .maximum = 15, - .step = 1, -#define BACKLIGHT_DEF 15 - .default_value = BACKLIGHT_DEF, - }, - .set = sd_setbacklight, - .get = sd_getbacklight, - }, -}; - -/* table of the disabled controls */ -static u32 ctrl_dis[NSENSORS] = { - [SENSOR_HV7131R] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) - | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_MI0360] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) - | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_MI1310_SOC] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_MI1320] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_MI1320_SOC] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_OV7660] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_OV7670] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_PO1200] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << LIGHTFREQ_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_PO3130NC] = - (1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX) - | (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX) - | (1 << SHARPNESS_IDX) - | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX) - | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX), - [SENSOR_POxxxx] = - (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX), -}; static const struct v4l2_pix_format vc0321_mode[] = { {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, @@ -3405,18 +3151,6 @@ static int sd_config(struct gspca_dev *gspca_dev, (id->idProduct == 0x0892 || id->idProduct == 0x0896)) sd->sensor = SENSOR_POxxxx; /* no probe */ - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->colors = COLOR_DEF; - sd->hflip = HFLIP_DEF; - sd->vflip = VFLIP_DEF; - sd->lightfreq = FREQ_DEF; - sd->sharpness = SHARPNESS_DEF; - sd->gain = GAIN_DEF; - sd->exposure = EXPOSURE_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->backlight = BACKLIGHT_DEF; - return 0; } @@ -3512,7 +3246,6 @@ static int sd_init(struct gspca_dev *gspca_dev) } } cam->npkt = npkt[sd->sensor]; - gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; if (sd->sensor == SENSOR_OV7670) sd->flags |= FL_HFLIP | FL_VFLIP; @@ -3534,14 +3267,11 @@ static int sd_init(struct gspca_dev *gspca_dev) return gspca_dev->usb_err; } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 data; - if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX)) - return; - data = sd->brightness; + data = val; if (data >= 0x80) data &= 0x7f; else @@ -3549,36 +3279,27 @@ static void setbrightness(struct gspca_dev *gspca_dev) i2c_write(gspca_dev, 0x98, &data, 1); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, u8 val) { - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX)) - return; - i2c_write(gspca_dev, 0x99, &sd->contrast, 1); + i2c_write(gspca_dev, 0x99, &val, 1); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, u8 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 data; - if (gspca_dev->ctrl_dis & (1 << COLORS_IDX)) - return; - data = sd->colors - (sd->colors >> 3) - 1; + data = val - (val >> 3) - 1; i2c_write(gspca_dev, 0x94, &data, 1); - i2c_write(gspca_dev, 0x95, &sd->colors, 1); + i2c_write(gspca_dev, 0x95, &val, 1); } -static void sethvflip(struct gspca_dev *gspca_dev) +static void sethvflip(struct gspca_dev *gspca_dev, bool hflip, bool vflip) { struct sd *sd = (struct sd *) gspca_dev; - u8 data[2], hflip, vflip; + u8 data[2]; - hflip = sd->hflip; if (sd->flags & FL_HFLIP) hflip = !hflip; - vflip = sd->vflip; if (sd->flags & FL_VFLIP) vflip = !vflip; switch (sd->sensor) { @@ -3610,7 +3331,7 @@ static void sethvflip(struct gspca_dev *gspca_dev) } } -static void setlightfreq(struct gspca_dev *gspca_dev) +static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; static const u8 (*ov7660_freq_tb[3])[4] = @@ -3618,10 +3339,10 @@ static void setlightfreq(struct gspca_dev *gspca_dev) if (sd->sensor != SENSOR_OV7660) return; - usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]); + usb_exchange(gspca_dev, ov7660_freq_tb[val]); } -static void setsharpness(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; u8 data; @@ -3630,51 +3351,41 @@ static void setsharpness(struct gspca_dev *gspca_dev) case SENSOR_PO1200: data = 0; i2c_write(gspca_dev, 0x03, &data, 1); - if (sd->sharpness < 0) + if (val < 0) data = 0x6a; else - data = 0xb5 + sd->sharpness * 3; + data = 0xb5 + val * 3; i2c_write(gspca_dev, 0x61, &data, 1); break; case SENSOR_POxxxx: - if (sd->sharpness < 0) + if (val < 0) data = 0x7e; /* def = max */ else - data = 0x60 + sd->sharpness * 0x0f; + data = 0x60 + val * 0x0f; i2c_write(gspca_dev, 0x59, &data, 1); break; } } -static void setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev, u8 val) { - struct sd *sd = (struct sd *) gspca_dev; - - if (gspca_dev->ctrl_dis & (1 << GAIN_IDX)) - return; - i2c_write(gspca_dev, 0x15, &sd->gain, 1); + i2c_write(gspca_dev, 0x15, &val, 1); } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 data; - if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) - return; - data = sd->exposure >> 8; + data = val >> 8; i2c_write(gspca_dev, 0x1a, &data, 1); - data = sd->exposure; + data = val; i2c_write(gspca_dev, 0x1b, &data, 1); } -static void setautogain(struct gspca_dev *gspca_dev) +static void setautogain(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; static const u8 data[2] = {0x28, 0x3c}; - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) - return; - i2c_write(gspca_dev, 0xd1, &data[sd->autogain], 1); + i2c_write(gspca_dev, 0xd1, &data[val], 1); } static void setgamma(struct gspca_dev *gspca_dev) @@ -3683,30 +3394,29 @@ static void setgamma(struct gspca_dev *gspca_dev) usb_exchange(gspca_dev, poxxxx_gamma); } -static void setbacklight(struct gspca_dev *gspca_dev) +static void setbacklight(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u16 v; u8 data; - data = (sd->backlight << 4) | 0x0f; + data = (val << 4) | 0x0f; i2c_write(gspca_dev, 0xaa, &data, 1); - v = 613 + 12 * sd->backlight; + v = 613 + 12 * val; data = v >> 8; i2c_write(gspca_dev, 0xc4, &data, 1); data = v; i2c_write(gspca_dev, 0xc5, &data, 1); - v = 1093 - 12 * sd->backlight; + v = 1093 - 12 * val; data = v >> 8; i2c_write(gspca_dev, 0xc6, &data, 1); data = v; i2c_write(gspca_dev, 0xc7, &data, 1); - v = 342 + 9 * sd->backlight; + v = 342 + 9 * val; data = v >> 8; i2c_write(gspca_dev, 0xc8, &data, 1); data = v; i2c_write(gspca_dev, 0xc9, &data, 1); - v = 702 - 9 * sd->backlight; + v = 702 - 9 * val; data = v >> 8; i2c_write(gspca_dev, 0xca, &data, 1); data = v; @@ -3833,14 +3543,6 @@ static int sd_start(struct gspca_dev *gspca_dev) /* case SENSOR_POxxxx: */ usb_exchange(gspca_dev, poxxxx_init_common); setgamma(gspca_dev); - setbacklight(gspca_dev); - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); - setsharpness(gspca_dev); - setautogain(gspca_dev); - setexposure(gspca_dev); - setgain(gspca_dev); usb_exchange(gspca_dev, poxxxx_init_start_3); if (mode) init = poxxxx_initQVGA; @@ -3873,8 +3575,6 @@ static int sd_start(struct gspca_dev *gspca_dev) break; } msleep(100); - sethvflip(gspca_dev); - setlightfreq(gspca_dev); } switch (sd->sensor) { case SENSOR_OV7670: @@ -3960,233 +3660,152 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; - - sd->colors = val; - if (gspca_dev->streaming) - setcolors(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->colors; - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hflip; - return 0; -} - -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; - *val = sd->vflip; - return 0; -} + gspca_dev->usb_err = 0; -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->lightfreq = val; - if (gspca_dev->streaming) - setlightfreq(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->lightfreq; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - if (gspca_dev->streaming) - setautogain(gspca_dev); + if (!gspca_dev->streaming && ctrl->id != V4L2_CID_POWER_LINE_FREQUENCY) + return 0; + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + sethvflip(gspca_dev, sd->hflip->val, sd->vflip->val); + break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + setautogain(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + setgain(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + setexposure(gspca_dev, ctrl->val); + break; + case V4L2_CID_BACKLIGHT_COMPENSATION: + setbacklight(gspca_dev, ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + setlightfreq(gspca_dev, ctrl->val); + break; + } return gspca_dev->usb_err; } -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_setbacklight(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->backlight = val; - if (gspca_dev->streaming) - setbacklight(gspca_dev); - - return gspca_dev->usb_err; -} +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; -static int sd_getbacklight(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_init_controls(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + bool has_brightness = false; + bool has_contrast = false; + bool has_sat = false; + bool has_hvflip = false; + bool has_freq = false; + bool has_backlight = false; + bool has_exposure = false; + bool has_autogain = false; + bool has_gain = false; + bool has_sharpness = false; - *val = sd->backlight; - return 0; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"}; + switch (sd->sensor) { + case SENSOR_HV7131R: + case SENSOR_MI0360: + case SENSOR_PO3130NC: + break; + case SENSOR_MI1310_SOC: + case SENSOR_MI1320: + case SENSOR_MI1320_SOC: + case SENSOR_OV7660: + has_hvflip = true; + break; + case SENSOR_OV7670: + has_hvflip = has_freq = true; + break; + case SENSOR_PO1200: + has_hvflip = has_sharpness = true; + break; + case SENSOR_POxxxx: + has_brightness = has_contrast = has_sat = has_backlight = + has_exposure = has_autogain = has_gain = + has_sharpness = true; + break; + } - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - if (menu->index >= ARRAY_SIZE(freq_nm)) - break; - strcpy((char *) menu->name, freq_nm[menu->index]); - return 0; + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 8); + if (has_brightness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + if (has_contrast) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 127); + if (has_sat) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 1, 127, 1, 63); + if (has_hvflip) { + sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); } - return -EINVAL; + if (has_sharpness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, -1, 2, 1, -1); + if (has_freq) + v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + if (has_autogain) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + if (has_gain) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 78, 1, 0); + if (has_exposure) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 4095, 1, 450); + if (has_backlight) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BACKLIGHT_COMPENSATION, 0, 15, 1, 15); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + if (sd->hflip) + v4l2_ctrl_cluster(2, &sd->hflip); + return 0; } /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), + .init_controls = sd_init_controls, .config = sd_config, .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, }; /* -- module initialisation -- */ @@ -4227,6 +3846,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c index 15a30f7a4b2a..b1a64b912666 100644 --- a/drivers/media/video/gspca/vicam.c +++ b/drivers/media/video/gspca/vicam.c @@ -44,17 +44,10 @@ MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(VICAM_FIRMWARE); -enum e_ctrl { - GAIN, - EXPOSURE, - NCTRL /* number of controls */ -}; - struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ struct work_struct work_struct; struct workqueue_struct *work_thread; - struct gspca_ctrl ctrls[NCTRL]; }; /* The vicam sensor has a resolution of 512 x 244, with I believe square @@ -86,31 +79,6 @@ static struct v4l2_pix_format vicam_mode[] = { .colorspace = V4L2_COLORSPACE_SRGB,}, }; -static const struct ctrl sd_ctrls[] = { -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 200, - }, - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 2047, - .step = 1, - .default_value = 256, - }, - }, -}; - static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request, u16 value, u16 index, u8 *data, u16 len) { @@ -146,12 +114,13 @@ static int vicam_set_camera_power(struct gspca_dev *gspca_dev, int state) */ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) { - struct sd *sd = (struct sd *)gspca_dev; int ret, unscaled_height, act_len = 0; u8 *req_data = gspca_dev->usb_buf; + s32 expo = v4l2_ctrl_g_ctrl(gspca_dev->exposure); + s32 gain = v4l2_ctrl_g_ctrl(gspca_dev->gain); memset(req_data, 0, 16); - req_data[0] = sd->ctrls[GAIN].val; + req_data[0] = gain; if (gspca_dev->width == 256) req_data[1] |= 0x01; /* low nibble x-scale */ if (gspca_dev->height <= 122) { @@ -167,9 +136,9 @@ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) else /* Up to 244 lines with req_data[3] == 0x08 */ req_data[3] = 0x08; /* vend? */ - if (sd->ctrls[EXPOSURE].val < 256) { + if (expo < 256) { /* Frame rate maxed out, use partial frame expo time */ - req_data[4] = 255 - sd->ctrls[EXPOSURE].val; + req_data[4] = 255 - expo; req_data[5] = 0x00; req_data[6] = 0x00; req_data[7] = 0x01; @@ -177,8 +146,8 @@ static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) /* Modify frame rate */ req_data[4] = 0x00; req_data[5] = 0x00; - req_data[6] = sd->ctrls[EXPOSURE].val & 0xFF; - req_data[7] = sd->ctrls[EXPOSURE].val >> 8; + req_data[6] = expo & 0xFF; + req_data[7] = expo >> 8; } req_data[8] = ((244 - unscaled_height) / 2) & ~0x01; /* vstart */ /* bytes 9-15 do not seem to affect exposure or image quality */ @@ -260,7 +229,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->bulk_size = 64; cam->cam_mode = vicam_mode; cam->nmodes = ARRAY_SIZE(vicam_mode); - cam->ctrls = sd->ctrls; INIT_WORK(&sd->work_struct, vicam_dostream); @@ -335,6 +303,24 @@ static void sd_stop0(struct gspca_dev *gspca_dev) vicam_set_camera_power(gspca_dev, 0); } +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 2); + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_EXPOSURE, 0, 2047, 1, 256); + gspca_dev->gain = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_GAIN, 0, 255, 1, 200); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + return 0; +} + /* Table of supported USB devices */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x04c1, 0x009d)}, @@ -347,10 +333,9 @@ MODULE_DEVICE_TABLE(usb, device_table); /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stop0 = sd_stop0, }; @@ -373,6 +358,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c index 27d2cef0692a..9e3a909e0a00 100644 --- a/drivers/media/video/gspca/w996Xcf.c +++ b/drivers/media/video/gspca/w996Xcf.c @@ -404,9 +404,14 @@ static void w9968cf_set_crop_window(struct sd *sd) } if (sd->sensor == SEN_OV7620) { - /* Sigh, this is dependend on the clock / framerate changes - made by the frequency control, sick. */ - if (sd->ctrls[FREQ].val == 1) { + /* + * Sigh, this is dependend on the clock / framerate changes + * made by the frequency control, sick. + * + * Note we cannot use v4l2_ctrl_g_ctrl here, as we get called + * from ov519.c:setfreq() with the ctrl lock held! + */ + if (sd->freq->val == 1) { start_cropx = 277; start_cropy = 37; } else { @@ -474,8 +479,9 @@ static void w9968cf_mode_init_regs(struct sd *sd) /* We may get called multiple times (usb isoc bw negotiat.) */ jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height, sd->gspca_dev.width, 0x22); /* JPEG 420 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual)); w9968cf_upload_quantizationtables(sd); + v4l2_ctrl_grab(sd->jpegqual, true); } /* Video Capture Control Register */ @@ -514,6 +520,7 @@ static void w9968cf_mode_init_regs(struct sd *sd) static void w9968cf_stop0(struct sd *sd) { + v4l2_ctrl_grab(sd->jpegqual, false); reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */ reg_w(sd, 0x16, 0x0000); /* stop video capture */ } diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c index ecada178bceb..13b8d395d210 100644 --- a/drivers/media/video/gspca/xirlink_cit.c +++ b/drivers/media/video/gspca/xirlink_cit.c @@ -53,6 +53,7 @@ MODULE_PARM_DESC(rca_input, /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + struct v4l2_ctrl *lighting; u8 model; #define CIT_MODEL0 0 /* bcd version 0.01 cams ie the xvp-500 */ #define CIT_MODEL1 1 /* The model 1 - 4 nomenclature comes from the old */ @@ -65,127 +66,10 @@ struct sd { u8 stop_on_control_change; u8 sof_read; u8 sof_len; - u8 contrast; - u8 brightness; - u8 hue; - u8 sharpness; - u8 lighting; - u8 hflip; }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); static void sd_stop0(struct gspca_dev *gspca_dev); -static const struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 63, - .step = 1, -#define BRIGHTNESS_DEFAULT 32 - .default_value = BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "contrast", - .minimum = 0, - .maximum = 20, - .step = 1, -#define CONTRAST_DEFAULT 10 - .default_value = CONTRAST_DEFAULT, - .flags = 0, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SD_HUE 2 - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 127, - .step = 1, -#define HUE_DEFAULT 63 - .default_value = HUE_DEFAULT, - .flags = 0, - }, - .set = sd_sethue, - .get = sd_gethue, - }, -#define SD_SHARPNESS 3 - { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 6, - .step = 1, -#define SHARPNESS_DEFAULT 3 - .default_value = SHARPNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setsharpness, - .get = sd_getsharpness, - }, -#define SD_LIGHTING 4 - { - { - .id = V4L2_CID_BACKLIGHT_COMPENSATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Lighting", - .minimum = 0, - .maximum = 2, - .step = 1, -#define LIGHTING_DEFAULT 1 - .default_value = LIGHTING_DEFAULT, - .flags = 0, - }, - .set = sd_setlighting, - .get = sd_getlighting, - }, -#define SD_HFLIP 5 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, -#define HFLIP_DEFAULT 0 - .default_value = HFLIP_DEFAULT, - }, - .set = sd_sethflip, - .get = sd_gethflip, - }, -}; - static const struct v4l2_pix_format cif_yuv_mode[] = { {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE, .bytesperline = 176, @@ -995,56 +879,36 @@ static int sd_config(struct gspca_dev *gspca_dev, case CIT_MODEL0: cam->cam_mode = model0_mode; cam->nmodes = ARRAY_SIZE(model0_mode); - gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP)); sd->sof_len = 4; break; case CIT_MODEL1: cam->cam_mode = cif_yuv_mode; cam->nmodes = ARRAY_SIZE(cif_yuv_mode); - gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP); sd->sof_len = 4; break; case CIT_MODEL2: cam->cam_mode = model2_mode + 1; /* no 160x120 */ cam->nmodes = 3; - gspca_dev->ctrl_dis = (1 << SD_CONTRAST) | - (1 << SD_SHARPNESS) | - (1 << SD_HFLIP); break; case CIT_MODEL3: cam->cam_mode = vga_yuv_mode; cam->nmodes = ARRAY_SIZE(vga_yuv_mode); - gspca_dev->ctrl_dis = (1 << SD_HUE) | - (1 << SD_LIGHTING) | - (1 << SD_HFLIP); sd->stop_on_control_change = 1; sd->sof_len = 4; break; case CIT_MODEL4: cam->cam_mode = model2_mode; cam->nmodes = ARRAY_SIZE(model2_mode); - gspca_dev->ctrl_dis = (1 << SD_CONTRAST) | - (1 << SD_SHARPNESS) | - (1 << SD_LIGHTING) | - (1 << SD_HFLIP); break; case CIT_IBM_NETCAM_PRO: cam->cam_mode = vga_yuv_mode; cam->nmodes = 2; /* no 640 x 480 */ cam->input_flags = V4L2_IN_ST_VFLIP; - gspca_dev->ctrl_dis = ~(1 << SD_CONTRAST); sd->stop_on_control_change = 1; sd->sof_len = 4; break; } - sd->brightness = BRIGHTNESS_DEFAULT; - sd->contrast = CONTRAST_DEFAULT; - sd->hue = HUE_DEFAULT; - sd->sharpness = SHARPNESS_DEFAULT; - sd->lighting = LIGHTING_DEFAULT; - sd->hflip = HFLIP_DEFAULT; - return 0; } @@ -1287,7 +1151,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static int cit_set_brightness(struct gspca_dev *gspca_dev) +static int cit_set_brightness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; int i; @@ -1299,19 +1163,19 @@ static int cit_set_brightness(struct gspca_dev *gspca_dev) break; case CIT_MODEL1: /* Model 1: Brightness range 0 - 63 */ - cit_Packet_Format1(gspca_dev, 0x0031, sd->brightness); - cit_Packet_Format1(gspca_dev, 0x0032, sd->brightness); - cit_Packet_Format1(gspca_dev, 0x0033, sd->brightness); + cit_Packet_Format1(gspca_dev, 0x0031, val); + cit_Packet_Format1(gspca_dev, 0x0032, val); + cit_Packet_Format1(gspca_dev, 0x0033, val); break; case CIT_MODEL2: /* Model 2: Brightness range 0x60 - 0xee */ /* Scale 0 - 63 to 0x60 - 0xee */ - i = 0x60 + sd->brightness * 2254 / 1000; + i = 0x60 + val * 2254 / 1000; cit_model2_Packet1(gspca_dev, 0x001a, i); break; case CIT_MODEL3: /* Model 3: Brightness range 'i' in [0x0C..0x3F] */ - i = sd->brightness; + i = val; if (i < 0x0c) i = 0x0c; cit_model3_Packet1(gspca_dev, 0x0036, i); @@ -1319,7 +1183,7 @@ static int cit_set_brightness(struct gspca_dev *gspca_dev) case CIT_MODEL4: /* Model 4: Brightness range 'i' in [0x04..0xb4] */ /* Scale 0 - 63 to 0x04 - 0xb4 */ - i = 0x04 + sd->brightness * 2794 / 1000; + i = 0x04 + val * 2794 / 1000; cit_model4_BrightnessPacket(gspca_dev, i); break; } @@ -1327,7 +1191,7 @@ static int cit_set_brightness(struct gspca_dev *gspca_dev) return 0; } -static int cit_set_contrast(struct gspca_dev *gspca_dev) +static int cit_set_contrast(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1335,16 +1199,16 @@ static int cit_set_contrast(struct gspca_dev *gspca_dev) case CIT_MODEL0: { int i; /* gain 0-15, 0-20 -> 0-15 */ - i = sd->contrast * 1000 / 1333; + i = val * 1000 / 1333; cit_write_reg(gspca_dev, i, 0x0422); /* gain 0-31, may not be lower then 0x0422, 0-20 -> 0-31 */ - i = sd->contrast * 2000 / 1333; + i = val * 2000 / 1333; cit_write_reg(gspca_dev, i, 0x0423); /* gain 0-127, may not be lower then 0x0423, 0-20 -> 0-63 */ - i = sd->contrast * 4000 / 1333; + i = val * 4000 / 1333; cit_write_reg(gspca_dev, i, 0x0424); /* gain 0-127, may not be lower then 0x0424, , 0-20 -> 0-127 */ - i = sd->contrast * 8000 / 1333; + i = val * 8000 / 1333; cit_write_reg(gspca_dev, i, 0x0425); break; } @@ -1355,7 +1219,7 @@ static int cit_set_contrast(struct gspca_dev *gspca_dev) case CIT_MODEL1: { /* Scale 0 - 20 to 15 - 0 */ - int i, new_contrast = (20 - sd->contrast) * 1000 / 1333; + int i, new_contrast = (20 - val) * 1000 / 1333; for (i = 0; i < cit_model1_ntries; i++) { cit_Packet_Format1(gspca_dev, 0x0014, new_contrast); cit_send_FF_04_02(gspca_dev); @@ -1377,20 +1241,20 @@ static int cit_set_contrast(struct gspca_dev *gspca_dev) { 0x01, 0x0e, 0x16 }, { 0x01, 0x10, 0x16 } /* Maximum */ }; - int i = sd->contrast / 3; + int i = val / 3; cit_model3_Packet1(gspca_dev, 0x0067, cv[i].cv1); cit_model3_Packet1(gspca_dev, 0x005b, cv[i].cv2); cit_model3_Packet1(gspca_dev, 0x005c, cv[i].cv3); break; } case CIT_IBM_NETCAM_PRO: - cit_model3_Packet1(gspca_dev, 0x005b, sd->contrast + 1); + cit_model3_Packet1(gspca_dev, 0x005b, val + 1); break; } return 0; } -static int cit_set_hue(struct gspca_dev *gspca_dev) +static int cit_set_hue(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1401,7 +1265,7 @@ static int cit_set_hue(struct gspca_dev *gspca_dev) /* No hue control for these models */ break; case CIT_MODEL2: - cit_model2_Packet1(gspca_dev, 0x0024, sd->hue); + cit_model2_Packet1(gspca_dev, 0x0024, val); /* cit_model2_Packet1(gspca_dev, 0x0020, sat); */ break; case CIT_MODEL3: { @@ -1409,7 +1273,7 @@ static int cit_set_hue(struct gspca_dev *gspca_dev) /* TESTME according to the ibmcam driver this does not work */ if (0) { /* Scale 0 - 127 to 0x05 - 0x37 */ - int i = 0x05 + sd->hue * 1000 / 2540; + int i = 0x05 + val * 1000 / 2540; cit_model3_Packet1(gspca_dev, 0x007e, i); } break; @@ -1435,14 +1299,14 @@ static int cit_set_hue(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 160, 0x012e); /* Red gain */ cit_write_reg(gspca_dev, 160, 0x0130); /* Blue gain */ cit_write_reg(gspca_dev, 0x8a28, 0x0124); - cit_write_reg(gspca_dev, sd->hue, 0x012d); /* Hue */ + cit_write_reg(gspca_dev, val, 0x012d); /* Hue */ cit_write_reg(gspca_dev, 0xf545, 0x0124); break; } return 0; } -static int cit_set_sharpness(struct gspca_dev *gspca_dev) +static int cit_set_sharpness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1459,7 +1323,7 @@ static int cit_set_sharpness(struct gspca_dev *gspca_dev) 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; for (i = 0; i < cit_model1_ntries; i++) - cit_PacketFormat2(gspca_dev, 0x0013, sa[sd->sharpness]); + cit_PacketFormat2(gspca_dev, 0x0013, sa[val]); break; } case CIT_MODEL3: @@ -1482,10 +1346,10 @@ static int cit_set_sharpness(struct gspca_dev *gspca_dev) { 0x03, 0x06, 0x05, 0x14 }, { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */ }; - cit_model3_Packet1(gspca_dev, 0x0060, sv[sd->sharpness].sv1); - cit_model3_Packet1(gspca_dev, 0x0061, sv[sd->sharpness].sv2); - cit_model3_Packet1(gspca_dev, 0x0062, sv[sd->sharpness].sv3); - cit_model3_Packet1(gspca_dev, 0x0063, sv[sd->sharpness].sv4); + cit_model3_Packet1(gspca_dev, 0x0060, sv[val].sv1); + cit_model3_Packet1(gspca_dev, 0x0061, sv[val].sv2); + cit_model3_Packet1(gspca_dev, 0x0062, sv[val].sv3); + cit_model3_Packet1(gspca_dev, 0x0063, sv[val].sv4); break; } } @@ -1510,7 +1374,7 @@ static int cit_set_sharpness(struct gspca_dev *gspca_dev) * 1/5/00 Created. * 2/20/00 Added support for Model 2 cameras. */ -static void cit_set_lighting(struct gspca_dev *gspca_dev) +static void cit_set_lighting(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1524,19 +1388,19 @@ static void cit_set_lighting(struct gspca_dev *gspca_dev) case CIT_MODEL1: { int i; for (i = 0; i < cit_model1_ntries; i++) - cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting); + cit_Packet_Format1(gspca_dev, 0x0027, val); break; } } } -static void cit_set_hflip(struct gspca_dev *gspca_dev) +static void cit_set_hflip(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; switch (sd->model) { case CIT_MODEL0: - if (sd->hflip) + if (val) cit_write_reg(gspca_dev, 0x0020, 0x0115); else cit_write_reg(gspca_dev, 0x0040, 0x0115); @@ -1831,7 +1695,8 @@ static int cit_start_model1(struct gspca_dev *gspca_dev) cit_PacketFormat2(gspca_dev, 0x13, 0x1a); /* Default lighting conditions */ - cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting); + cit_Packet_Format1(gspca_dev, 0x0027, + v4l2_ctrl_g_ctrl(sd->lighting)); } /* Assorted init */ @@ -2049,9 +1914,10 @@ static int cit_start_model2(struct gspca_dev *gspca_dev) break; } - /* FIXME this cannot be changed while streaming, so we - should report a grabbed flag for this control. */ - cit_model2_Packet1(gspca_dev, 0x0028, sd->lighting); + cit_model2_Packet1(gspca_dev, 0x0028, v4l2_ctrl_g_ctrl(sd->lighting)); + /* model2 cannot change the backlight compensation while streaming */ + v4l2_ctrl_grab(sd->lighting, true); + /* color balance rg2 */ cit_model2_Packet1(gspca_dev, 0x001e, 0x002f); /* saturation */ @@ -2755,13 +2621,6 @@ static int sd_start(struct gspca_dev *gspca_dev) break; } - cit_set_brightness(gspca_dev); - cit_set_contrast(gspca_dev); - cit_set_hue(gspca_dev); - cit_set_sharpness(gspca_dev); - cit_set_lighting(gspca_dev); - cit_set_hflip(gspca_dev); - /* Program max isoc packet size */ cit_write_reg(gspca_dev, packet_size >> 8, 0x0106); cit_write_reg(gspca_dev, packet_size & 0xff, 0x0107); @@ -2857,6 +2716,8 @@ static void sd_stop0(struct gspca_dev *gspca_dev) cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */ break; case CIT_MODEL2: + v4l2_ctrl_grab(sd->lighting, false); + /* Fall through! */ case CIT_MODEL4: cit_model2_Packet1(gspca_dev, 0x0030, 0x0004); @@ -3055,152 +2916,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_brightness(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_contrast(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - - return 0; -} - -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_hue(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - return 0; -} - -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hue; - - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_sharpness(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - return 0; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - - return 0; -} - -static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->lighting = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_lighting(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - return 0; -} - -static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->lighting; - - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) { - if (sd->stop_on_control_change) - sd_stopN(gspca_dev); - cit_set_hflip(gspca_dev); - if (sd->stop_on_control_change) - cit_restart_stream(gspca_dev); - } - return 0; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hflip; - - return 0; -} - #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) static void cit_check_button(struct gspca_dev *gspca_dev) { @@ -3234,13 +2949,117 @@ static void cit_check_button(struct gspca_dev *gspca_dev) } #endif +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + if (sd->stop_on_control_change) + sd_stopN(gspca_dev); + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + cit_set_brightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + cit_set_contrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_HUE: + cit_set_hue(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + cit_set_hflip(gspca_dev, ctrl->val); + break; + case V4L2_CID_SHARPNESS: + cit_set_sharpness(gspca_dev, ctrl->val); + break; + case V4L2_CID_BACKLIGHT_COMPENSATION: + cit_set_lighting(gspca_dev, ctrl->val); + break; + } + if (sd->stop_on_control_change) + cit_restart_stream(gspca_dev); + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + bool has_brightness; + bool has_contrast; + bool has_hue; + bool has_sharpness; + bool has_lighting; + bool has_hflip; + + has_brightness = has_contrast = has_hue = + has_sharpness = has_hflip = has_lighting = false; + switch (sd->model) { + case CIT_MODEL0: + has_contrast = has_hflip = true; + break; + case CIT_MODEL1: + has_brightness = has_contrast = + has_sharpness = has_lighting = true; + break; + case CIT_MODEL2: + has_brightness = has_hue = has_lighting = true; + break; + case CIT_MODEL3: + has_brightness = has_contrast = has_sharpness = true; + break; + case CIT_MODEL4: + has_brightness = has_hue = true; + break; + case CIT_IBM_NETCAM_PRO: + has_brightness = has_hue = + has_sharpness = has_hflip = has_lighting = true; + break; + } + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 5); + if (has_brightness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 63, 1, 32); + if (has_contrast) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 20, 1, 10); + if (has_hue) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HUE, 0, 127, 1, 63); + if (has_sharpness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 6, 1, 3); + if (has_lighting) + sd->lighting = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BACKLIGHT_COMPENSATION, 0, 2, 1, 1); + if (has_hflip) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, @@ -3253,10 +3072,9 @@ static const struct sd_desc sd_desc = { static const struct sd_desc sd_desc_isoc_nego = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .isoc_init = sd_isoc_init, .isoc_nego = sd_isoc_nego, @@ -3320,6 +3138,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/ibmmpeg2.h b/drivers/media/video/ibmmpeg2.h deleted file mode 100644 index 68e10387c498..000000000000 --- a/drivers/media/video/ibmmpeg2.h +++ /dev/null @@ -1,94 +0,0 @@ -/* ibmmpeg2.h - IBM MPEGCD21 definitions */ - -#ifndef __IBM_MPEG2__ -#define __IBM_MPEG2__ - -/* Define all MPEG Decoder registers */ -/* Chip Control and Status */ -#define IBM_MP2_CHIP_CONTROL 0x200*2 -#define IBM_MP2_CHIP_MODE 0x201*2 -/* Timer Control and Status */ -#define IBM_MP2_SYNC_STC2 0x202*2 -#define IBM_MP2_SYNC_STC1 0x203*2 -#define IBM_MP2_SYNC_STC0 0x204*2 -#define IBM_MP2_SYNC_PTS2 0x205*2 -#define IBM_MP2_SYNC_PTS1 0x206*2 -#define IBM_MP2_SYNC_PTS0 0x207*2 -/* Video FIFO Control */ -#define IBM_MP2_FIFO 0x208*2 -#define IBM_MP2_FIFOW 0x100*2 -#define IBM_MP2_FIFO_STAT 0x209*2 -#define IBM_MP2_RB_THRESHOLD 0x22b*2 -/* Command buffer */ -#define IBM_MP2_COMMAND 0x20a*2 -#define IBM_MP2_CMD_DATA 0x20b*2 -#define IBM_MP2_CMD_STAT 0x20c*2 -#define IBM_MP2_CMD_ADDR 0x20d*2 -/* Internal Processor Control and Status */ -#define IBM_MP2_PROC_IADDR 0x20e*2 -#define IBM_MP2_PROC_IDATA 0x20f*2 -#define IBM_MP2_WR_PROT 0x235*2 -/* DRAM Access */ -#define IBM_MP2_DRAM_ADDR 0x210*2 -#define IBM_MP2_DRAM_DATA 0x212*2 -#define IBM_MP2_DRAM_CMD_STAT 0x213*2 -#define IBM_MP2_BLOCK_SIZE 0x23b*2 -#define IBM_MP2_SRC_ADDR 0x23c*2 -/* Onscreen Display */ -#define IBM_MP2_OSD_ADDR 0x214*2 -#define IBM_MP2_OSD_DATA 0x215*2 -#define IBM_MP2_OSD_MODE 0x217*2 -#define IBM_MP2_OSD_LINK_ADDR 0x229*2 -#define IBM_MP2_OSD_SIZE 0x22a*2 -/* Interrupt Control */ -#define IBM_MP2_HOST_INT 0x218*2 -#define IBM_MP2_MASK0 0x219*2 -#define IBM_MP2_HOST_INT1 0x23e*2 -#define IBM_MP2_MASK1 0x23f*2 -/* Audio Control */ -#define IBM_MP2_AUD_IADDR 0x21a*2 -#define IBM_MP2_AUD_IDATA 0x21b*2 -#define IBM_MP2_AUD_FIFO 0x21c*2 -#define IBM_MP2_AUD_FIFOW 0x101*2 -#define IBM_MP2_AUD_CTL 0x21d*2 -#define IBM_MP2_BEEP_CTL 0x21e*2 -#define IBM_MP2_FRNT_ATTEN 0x22d*2 -/* Display Control */ -#define IBM_MP2_DISP_MODE 0x220*2 -#define IBM_MP2_DISP_DLY 0x221*2 -#define IBM_MP2_VBI_CTL 0x222*2 -#define IBM_MP2_DISP_LBOR 0x223*2 -#define IBM_MP2_DISP_TBOR 0x224*2 -/* Polarity Control */ -#define IBM_MP2_INFC_CTL 0x22c*2 - -/* control commands */ -#define IBM_MP2_PLAY 0 -#define IBM_MP2_PAUSE 1 -#define IBM_MP2_SINGLE_FRAME 2 -#define IBM_MP2_FAST_FORWARD 3 -#define IBM_MP2_SLOW_MOTION 4 -#define IBM_MP2_IMED_NORM_PLAY 5 -#define IBM_MP2_RESET_WINDOW 6 -#define IBM_MP2_FREEZE_FRAME 7 -#define IBM_MP2_RESET_VID_RATE 8 -#define IBM_MP2_CONFIG_DECODER 9 -#define IBM_MP2_CHANNEL_SWITCH 10 -#define IBM_MP2_RESET_AUD_RATE 11 -#define IBM_MP2_PRE_OP_CHN_SW 12 -#define IBM_MP2_SET_STILL_MODE 14 - -/* Define Xilinx FPGA Internal Registers */ - -/* general control register 0 */ -#define XILINX_CTL0 0x600 -/* genlock delay resister 1 */ -#define XILINX_GLDELAY 0x602 -/* send 16 bits to CS3310 port */ -#define XILINX_CS3310 0x604 -/* send 16 bits to CS3310 and complete */ -#define XILINX_CS3310_CMPLT 0x60c -/* pulse width modulator control */ -#define XILINX_PWM 0x606 - -#endif diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index f7d57b3f2842..32a591062d0b 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1830,18 +1830,6 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio, return 0; } -long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct video_device *vfd = video_devdata(filp); - long ret; - - if (ivtv_debug & IVTV_DBGFLG_IOCTL) - vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; - ret = video_ioctl2(filp, cmd, arg); - vfd->debug = 0; - return ret; -} - static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { .vidioc_querycap = ivtv_querycap, .vidioc_s_audio = ivtv_s_audio, diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h index 89185caeafae..7c553d16579b 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.h +++ b/drivers/media/video/ivtv/ivtv-ioctl.h @@ -31,6 +31,5 @@ void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std); void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std); int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); int ivtv_s_input(struct file *file, void *fh, unsigned int inp); -long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); #endif diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 6738592aa35d..87990c5f0910 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -50,7 +50,7 @@ static const struct v4l2_file_operations ivtv_v4l2_enc_fops = { .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, .open = ivtv_v4l2_open, - .unlocked_ioctl = ivtv_v4l2_ioctl, + .unlocked_ioctl = video_ioctl2, .release = ivtv_v4l2_close, .poll = ivtv_v4l2_enc_poll, }; @@ -60,7 +60,7 @@ static const struct v4l2_file_operations ivtv_v4l2_dec_fops = { .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, .open = ivtv_v4l2_open, - .unlocked_ioctl = ivtv_v4l2_ioctl, + .unlocked_ioctl = video_ioctl2, .release = ivtv_v4l2_close, .poll = ivtv_v4l2_dec_poll, }; diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/video/m5mols/Kconfig index 302dc3d70193..dc8c2505907e 100644 --- a/drivers/media/video/m5mols/Kconfig +++ b/drivers/media/video/m5mols/Kconfig @@ -1,5 +1,6 @@ config VIDEO_M5MOLS tristate "Fujitsu M-5MOLS 8MP sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT ---help--- This driver supports Fujitsu M-5MOLS camera sensor with ISP diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c index 392a028730e2..fdbc205a2969 100644 --- a/drivers/media/video/m5mols/m5mols_controls.c +++ b/drivers/media/video/m5mols/m5mols_controls.c @@ -527,8 +527,8 @@ static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { /* Supported manual ISO values */ static const s64 iso_qmenu[] = { - /* AE_ISO: 0x01...0x07 */ - 50, 100, 200, 400, 800, 1600, 3200 + /* AE_ISO: 0x01...0x07 (ISO: 50...3200) */ + 50000, 100000, 200000, 400000, 800000, 1600000, 3200000 }; /* Supported Exposure Bias values, -2.0EV...+2.0EV */ diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index 3945556f5733..7efe9ad7acc7 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -27,6 +27,8 @@ #include <media/v4l2-mem2mem.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #include <media/videobuf2-vmalloc.h> #define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev" @@ -60,6 +62,10 @@ MODULE_VERSION("0.1.1"); #define MEM2MEM_COLOR_STEP (0xff >> 4) #define MEM2MEM_NUM_TILES 8 +/* Flags that indicate processing mode */ +#define MEM2MEM_HFLIP (1 << 0) +#define MEM2MEM_VFLIP (1 << 1) + #define dprintk(dev, fmt, arg...) \ v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) @@ -97,6 +103,8 @@ static struct m2mtest_fmt formats[] = { }, }; +#define NUM_FORMATS ARRAY_SIZE(formats) + /* Per-queue, driver-specific private data */ struct m2mtest_q_data { unsigned int width; @@ -110,32 +118,8 @@ enum { V4L2_M2M_DST = 1, }; -#define V4L2_CID_TRANS_TIME_MSEC V4L2_CID_PRIVATE_BASE -#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_PRIVATE_BASE + 1) - -static struct v4l2_queryctrl m2mtest_ctrls[] = { - { - .id = V4L2_CID_TRANS_TIME_MSEC, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Transaction time (msec)", - .minimum = 1, - .maximum = 10000, - .step = 100, - .default_value = 1000, - .flags = 0, - }, { - .id = V4L2_CID_TRANS_NUM_BUFS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Buffers per transaction", - .minimum = 1, - .maximum = MEM2MEM_DEF_NUM_BUFS, - .step = 1, - .default_value = 1, - .flags = 0, - }, -}; - -#define NUM_FORMATS ARRAY_SIZE(formats) +#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000) +#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001) static struct m2mtest_fmt *find_format(struct v4l2_format *f) { @@ -168,8 +152,11 @@ struct m2mtest_dev { }; struct m2mtest_ctx { + struct v4l2_fh fh; struct m2mtest_dev *dev; + struct v4l2_ctrl_handler hdl; + /* Processed buffers in this transaction */ u8 num_processed; @@ -181,12 +168,22 @@ struct m2mtest_ctx { /* Abort requested by m2m */ int aborting; + /* Processing mode */ + int mode; + + enum v4l2_colorspace colorspace; + struct v4l2_m2m_ctx *m2m_ctx; /* Source and destination queue data */ struct m2mtest_q_data q_data[2]; }; +static inline struct m2mtest_ctx *file2ctx(struct file *file) +{ + return container_of(file->private_data, struct m2mtest_ctx, fh); +} + static struct m2mtest_q_data *get_q_data(struct m2mtest_ctx *ctx, enum v4l2_buf_type type) { @@ -202,18 +199,6 @@ static struct m2mtest_q_data *get_q_data(struct m2mtest_ctx *ctx, } -static struct v4l2_queryctrl *get_ctrl(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(m2mtest_ctrls); ++i) { - if (id == m2mtest_ctrls[i].id) - return &m2mtest_ctrls[i]; - } - - return NULL; -} - static int device_process(struct m2mtest_ctx *ctx, struct vb2_buffer *in_vb, struct vb2_buffer *out_vb) @@ -249,19 +234,84 @@ static int device_process(struct m2mtest_ctx *ctx, bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES; w = 0; - for (y = 0; y < height; ++y) { - for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { - if (w & 0x1) { - for (x = 0; x < tile_w; ++x) - *p_out++ = *p_in++ + MEM2MEM_COLOR_STEP; - } else { - for (x = 0; x < tile_w; ++x) - *p_out++ = *p_in++ - MEM2MEM_COLOR_STEP; + switch (ctx->mode) { + case MEM2MEM_HFLIP | MEM2MEM_VFLIP: + p_out += bytesperline * height - bytes_left; + for (y = 0; y < height; ++y) { + for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { + if (w & 0x1) { + for (x = 0; x < tile_w; ++x) + *--p_out = *p_in++ + + MEM2MEM_COLOR_STEP; + } else { + for (x = 0; x < tile_w; ++x) + *--p_out = *p_in++ - + MEM2MEM_COLOR_STEP; + } + ++w; } - ++w; + p_in += bytes_left; + p_out -= bytes_left; + } + break; + + case MEM2MEM_HFLIP: + for (y = 0; y < height; ++y) { + p_out += MEM2MEM_NUM_TILES * tile_w; + for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { + if (w & 0x01) { + for (x = 0; x < tile_w; ++x) + *--p_out = *p_in++ + + MEM2MEM_COLOR_STEP; + } else { + for (x = 0; x < tile_w; ++x) + *--p_out = *p_in++ - + MEM2MEM_COLOR_STEP; + } + ++w; + } + p_in += bytes_left; + p_out += bytesperline; + } + break; + + case MEM2MEM_VFLIP: + p_out += bytesperline * (height - 1); + for (y = 0; y < height; ++y) { + for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { + if (w & 0x1) { + for (x = 0; x < tile_w; ++x) + *p_out++ = *p_in++ + + MEM2MEM_COLOR_STEP; + } else { + for (x = 0; x < tile_w; ++x) + *p_out++ = *p_in++ - + MEM2MEM_COLOR_STEP; + } + ++w; + } + p_in += bytes_left; + p_out += bytes_left - 2 * bytesperline; + } + break; + + default: + for (y = 0; y < height; ++y) { + for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { + if (w & 0x1) { + for (x = 0; x < tile_w; ++x) + *p_out++ = *p_in++ + + MEM2MEM_COLOR_STEP; + } else { + for (x = 0; x < tile_w; ++x) + *p_out++ = *p_in++ - + MEM2MEM_COLOR_STEP; + } + ++w; + } + p_in += bytes_left; + p_out += bytes_left; } - p_in += bytes_left; - p_out += bytes_left; } return 0; @@ -380,10 +430,9 @@ static int vidioc_querycap(struct file *file, void *priv, { strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); - cap->bus_info[0] = 0; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT - | V4L2_CAP_STREAMING; - + strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info)); + cap->capabilities = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -446,6 +495,7 @@ static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) f->fmt.pix.pixelformat = q_data->fmt->fourcc; f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3; f->fmt.pix.sizeimage = q_data->sizeimage; + f->fmt.pix.colorspace = ctx->colorspace; return 0; } @@ -453,13 +503,13 @@ static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) static int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file2ctx(file), f); } static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file2ctx(file), f); } static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt) @@ -498,7 +548,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct m2mtest_fmt *fmt; - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = file2ctx(file); fmt = find_format(f); if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { @@ -507,6 +557,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.pixelformat); return -EINVAL; } + f->fmt.pix.colorspace = ctx->colorspace; return vidioc_try_fmt(f, fmt); } @@ -515,7 +566,7 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct m2mtest_fmt *fmt; - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = file2ctx(file); fmt = find_format(f); if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { @@ -524,6 +575,8 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, f->fmt.pix.pixelformat); return -EINVAL; } + if (!f->fmt.pix.colorspace) + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; return vidioc_try_fmt(f, fmt); } @@ -568,25 +621,29 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (ret) return ret; - return vidioc_s_fmt(priv, f); + return vidioc_s_fmt(file2ctx(file), f); } static int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { + struct m2mtest_ctx *ctx = file2ctx(file); int ret; ret = vidioc_try_fmt_vid_out(file, priv, f); if (ret) return ret; - return vidioc_s_fmt(priv, f); + ret = vidioc_s_fmt(file2ctx(file), f); + if (!ret) + ctx->colorspace = f->fmt.pix.colorspace; + return ret; } static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = file2ctx(file); return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); } @@ -594,21 +651,21 @@ static int vidioc_reqbufs(struct file *file, void *priv, static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = file2ctx(file); return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); } static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = file2ctx(file); return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); } static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = file2ctx(file); return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } @@ -616,7 +673,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = file2ctx(file); return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); } @@ -624,79 +681,37 @@ static int vidioc_streamon(struct file *file, void *priv, static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = file2ctx(file); return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl) { - struct v4l2_queryctrl *c; - - c = get_ctrl(qc->id); - if (!c) - return -EINVAL; - - *qc = *c; - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct m2mtest_ctx *ctx = priv; + struct m2mtest_ctx *ctx = + container_of(ctrl->handler, struct m2mtest_ctx, hdl); switch (ctrl->id) { - case V4L2_CID_TRANS_TIME_MSEC: - ctrl->value = ctx->transtime; + case V4L2_CID_HFLIP: + if (ctrl->val) + ctx->mode |= MEM2MEM_HFLIP; + else + ctx->mode &= ~MEM2MEM_HFLIP; break; - case V4L2_CID_TRANS_NUM_BUFS: - ctrl->value = ctx->translen; + case V4L2_CID_VFLIP: + if (ctrl->val) + ctx->mode |= MEM2MEM_VFLIP; + else + ctx->mode &= ~MEM2MEM_VFLIP; break; - default: - v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); - return -EINVAL; - } - - return 0; -} - -static int check_ctrl_val(struct m2mtest_ctx *ctx, struct v4l2_control *ctrl) -{ - struct v4l2_queryctrl *c; - - c = get_ctrl(ctrl->id); - if (!c) - return -EINVAL; - - if (ctrl->value < c->minimum || ctrl->value > c->maximum) { - v4l2_err(&ctx->dev->v4l2_dev, "Value out of range\n"); - return -ERANGE; - } - - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct m2mtest_ctx *ctx = priv; - int ret = 0; - - ret = check_ctrl_val(ctx, ctrl); - if (ret != 0) - return ret; - - switch (ctrl->id) { case V4L2_CID_TRANS_TIME_MSEC: - ctx->transtime = ctrl->value; + ctx->transtime = ctrl->val; break; case V4L2_CID_TRANS_NUM_BUFS: - ctx->translen = ctrl->value; + ctx->translen = ctrl->val; break; default: @@ -707,6 +722,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return 0; } +static const struct v4l2_ctrl_ops m2mtest_ctrl_ops = { + .s_ctrl = m2mtest_s_ctrl, +}; + static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { .vidioc_querycap = vidioc_querycap, @@ -729,10 +748,8 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; @@ -844,6 +861,28 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds return vb2_queue_init(dst_vq); } +static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = { + .ops = &m2mtest_ctrl_ops, + .id = V4L2_CID_TRANS_TIME_MSEC, + .name = "Transaction Time (msec)", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = 1001, + .min = 1, + .max = 10001, + .step = 100, +}; + +static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = { + .ops = &m2mtest_ctrl_ops, + .id = V4L2_CID_TRANS_NUM_BUFS, + .name = "Buffers Per Transaction", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = 1, + .min = 1, + .max = MEM2MEM_DEF_NUM_BUFS, + .step = 1, +}; + /* * File operations */ @@ -851,29 +890,51 @@ static int m2mtest_open(struct file *file) { struct m2mtest_dev *dev = video_drvdata(file); struct m2mtest_ctx *ctx = NULL; + struct v4l2_ctrl_handler *hdl; ctx = kzalloc(sizeof *ctx, GFP_KERNEL); if (!ctx) return -ENOMEM; - file->private_data = ctx; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; ctx->dev = dev; - ctx->translen = MEM2MEM_DEF_TRANSLEN; - ctx->transtime = MEM2MEM_DEF_TRANSTIME; - ctx->num_processed = 0; + hdl = &ctx->hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_time_msec, NULL); + v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_num_bufs, NULL); + if (hdl->error) { + int err = hdl->error; + + v4l2_ctrl_handler_free(hdl); + return err; + } + ctx->fh.ctrl_handler = hdl; + v4l2_ctrl_handler_setup(hdl); ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0]; - ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; + ctx->q_data[V4L2_M2M_SRC].width = 640; + ctx->q_data[V4L2_M2M_SRC].height = 480; + ctx->q_data[V4L2_M2M_SRC].sizeimage = + ctx->q_data[V4L2_M2M_SRC].width * + ctx->q_data[V4L2_M2M_SRC].height * + (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3); + ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; + ctx->colorspace = V4L2_COLORSPACE_REC709; ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); if (IS_ERR(ctx->m2m_ctx)) { int ret = PTR_ERR(ctx->m2m_ctx); + v4l2_ctrl_handler_free(hdl); kfree(ctx); return ret; } + v4l2_fh_add(&ctx->fh); atomic_inc(&dev->num_inst); dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); @@ -884,10 +945,13 @@ static int m2mtest_open(struct file *file) static int m2mtest_release(struct file *file) { struct m2mtest_dev *dev = video_drvdata(file); - struct m2mtest_ctx *ctx = file->private_data; + struct m2mtest_ctx *ctx = file2ctx(file); dprintk(dev, "Releasing instance %p\n", ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->hdl); v4l2_m2m_ctx_release(ctx->m2m_ctx); kfree(ctx); @@ -899,14 +963,14 @@ static int m2mtest_release(struct file *file) static unsigned int m2mtest_poll(struct file *file, struct poll_table_struct *wait) { - struct m2mtest_ctx *ctx = file->private_data; + struct m2mtest_ctx *ctx = file2ctx(file); return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); } static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma) { - struct m2mtest_ctx *ctx = file->private_data; + struct m2mtest_ctx *ctx = file2ctx(file); return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); } diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 7e648183f157..00583f5fd26b 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -22,7 +22,7 @@ /* * mt9m001 i2c address 0x5d - * The platform has to define ctruct i2c_board_info objects and link to them + * The platform has to define struct i2c_board_info objects and link to them * from struct soc_camera_link */ diff --git a/drivers/media/video/mt9m032.c b/drivers/media/video/mt9m032.c index 3c1e626139b7..445359c96113 100644 --- a/drivers/media/video/mt9m032.c +++ b/drivers/media/video/mt9m032.c @@ -688,11 +688,17 @@ static const struct v4l2_subdev_ops mt9m032_ops = { static int mt9m032_probe(struct i2c_client *client, const struct i2c_device_id *devid) { + struct mt9m032_platform_data *pdata = client->dev.platform_data; struct i2c_adapter *adapter = client->adapter; struct mt9m032 *sensor; int chip_version; int ret; + if (pdata == NULL) { + dev_err(&client->dev, "No platform data\n"); + return -EINVAL; + } + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { dev_warn(&client->dev, "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); @@ -708,7 +714,7 @@ static int mt9m032_probe(struct i2c_client *client, mutex_init(&sensor->lock); - sensor->pdata = client->dev.platform_data; + sensor->pdata = pdata; v4l2_i2c_subdev_init(&sensor->subdev, client, &mt9m032_ops); sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -738,7 +744,7 @@ static int mt9m032_probe(struct i2c_client *client, sensor->format.field = V4L2_FIELD_NONE; sensor->format.colorspace = V4L2_COLORSPACE_SRGB; - v4l2_ctrl_handler_init(&sensor->ctrls, 4); + v4l2_ctrl_handler_init(&sensor->ctrls, 5); v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, V4L2_CID_GAIN, 0, 127, 1, 64); @@ -754,6 +760,9 @@ static int mt9m032_probe(struct i2c_client *client, V4L2_CID_EXPOSURE, MT9M032_SHUTTER_WIDTH_MIN, MT9M032_SHUTTER_WIDTH_MAX, 1, MT9M032_SHUTTER_WIDTH_DEF); + v4l2_ctrl_new_std(&sensor->ctrls, &mt9m032_ctrl_ops, + V4L2_CID_PIXEL_RATE, pdata->pix_clock, + pdata->pix_clock, 1, pdata->pix_clock); if (sensor->ctrls.error) { ret = sensor->ctrls.error; diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index b0c529964329..863d722dda06 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -214,7 +214,6 @@ struct mt9m111 { int power_count; const struct mt9m111_datafmt *fmt; int lastpage; /* PageMap cache value */ - unsigned char datawidth; }; /* Find a data format by a pixel code */ diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c index 8f061d9ac443..3be537ef22d2 100644 --- a/drivers/media/video/mt9p031.c +++ b/drivers/media/video/mt9p031.c @@ -950,7 +950,7 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->model = did->driver_data; mt9p031->reset = -1; - v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 4); + v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 5); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN, @@ -963,6 +963,9 @@ static int mt9p031_probe(struct i2c_client *client, V4L2_CID_HFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, + V4L2_CID_PIXEL_RATE, pdata->target_freq, + pdata->target_freq, 1, pdata->target_freq); for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i) v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL); diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c index 49ca3cbfc6f1..6d343adf891d 100644 --- a/drivers/media/video/mt9t001.c +++ b/drivers/media/video/mt9t001.c @@ -691,7 +691,7 @@ static int mt9t001_video_probe(struct i2c_client *client) return ret; /* Configure the pixel clock polarity */ - if (pdata && pdata->clk_pol) { + if (pdata->clk_pol) { ret = mt9t001_write(client, MT9T001_PIXEL_CLOCK, MT9T001_PIXEL_CLOCK_INVERT); if (ret < 0) @@ -715,10 +715,16 @@ static int mt9t001_video_probe(struct i2c_client *client) static int mt9t001_probe(struct i2c_client *client, const struct i2c_device_id *did) { + struct mt9t001_platform_data *pdata = client->dev.platform_data; struct mt9t001 *mt9t001; unsigned int i; int ret; + if (pdata == NULL) { + dev_err(&client->dev, "No platform data\n"); + return -EINVAL; + } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { dev_warn(&client->adapter->dev, @@ -735,7 +741,7 @@ static int mt9t001_probe(struct i2c_client *client, return -ENOMEM; v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) + - ARRAY_SIZE(mt9t001_gains) + 2); + ARRAY_SIZE(mt9t001_gains) + 3); v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN, @@ -743,6 +749,9 @@ static int mt9t001_probe(struct i2c_client *client, MT9T001_SHUTTER_WIDTH_DEF); v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, V4L2_CID_BLACK_LEVEL, 1, 1, 1, 1); + v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, + V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk, + 1, pdata->ext_clk); for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i) v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL); diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index bf63417adb8f..72479247522a 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -23,7 +23,7 @@ /* * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c - * The platform has to define ctruct i2c_board_info objects and link to them + * The platform has to define struct i2c_board_info objects and link to them * from struct soc_camera_link */ diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 4296a8350298..d2e6f82ecfac 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -43,6 +43,7 @@ #include <asm/fiq.h> #include <mach/dma-mx1-mx2.h> #include <mach/hardware.h> +#include <mach/irqs.h> #include <mach/mx1_camera.h> /* diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index 41f9a254b245..637bde8aca28 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c @@ -83,6 +83,7 @@ #define CSICR1_INV_DATA (1 << 3) #define CSICR1_INV_PCLK (1 << 2) #define CSICR1_REDGE (1 << 1) +#define CSICR1_FMT_MASK (CSICR1_PACK_DIR | CSICR1_SWAP16_EN) #define SHIFT_STATFF_LEVEL 22 #define SHIFT_RXFF_LEVEL 19 @@ -230,6 +231,7 @@ struct mx2_prp_cfg { u32 src_pixel; u32 ch1_pixel; u32 irq_flags; + u32 csicr1; }; /* prp resizing parameters */ @@ -330,6 +332,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { .ch1_pixel = 0x2ca00565, /* RGB565 */ .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | PRP_INTR_CH1FC | PRP_INTR_LBOVF, + .csicr1 = 0, } }, { @@ -343,6 +346,21 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = { .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | PRP_INTR_CH2FC | PRP_INTR_LBOVF | PRP_INTR_CH2OVF, + .csicr1 = CSICR1_PACK_DIR, + } + }, + { + .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8, + .out_fmt = V4L2_PIX_FMT_YUV420, + .cfg = { + .channel = 2, + .in_fmt = PRP_CNTL_DATA_IN_YUV422, + .out_fmt = PRP_CNTL_CH2_OUT_YUV420, + .src_pixel = 0x22000888, /* YUV422 (YUYV) */ + .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | + PRP_INTR_CH2FC | PRP_INTR_LBOVF | + PRP_INTR_CH2OVF, + .csicr1 = CSICR1_SWAP16_EN, } }, }; @@ -1015,14 +1033,14 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) return ret; } + csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1; + if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) csicr1 |= CSICR1_REDGE; if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) csicr1 |= CSICR1_SOF_POL; if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) csicr1 |= CSICR1_HSYNC_POL; - if (pcdev->platform_flags & MX2_CAMERA_SWAP16) - csicr1 |= CSICR1_SWAP16_EN; if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) csicr1 |= CSICR1_EXT_VSYNC; if (pcdev->platform_flags & MX2_CAMERA_CCIR) @@ -1033,8 +1051,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) csicr1 |= CSICR1_GCLK_MODE; if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) csicr1 |= CSICR1_INV_DATA; - if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB) - csicr1 |= CSICR1_PACK_DIR; pcdev->csicr1 = csicr1; @@ -1109,7 +1125,8 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, return 0; } - if (code == V4L2_MBUS_FMT_YUYV8_2X8) { + if (code == V4L2_MBUS_FMT_YUYV8_2X8 || + code == V4L2_MBUS_FMT_UYVY8_2X8) { formats++; if (xlate) { /* diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c index 0bd5815de369..5f8a6f5b98f9 100644 --- a/drivers/media/video/mx2_emmaprp.c +++ b/drivers/media/video/mx2_emmaprp.c @@ -396,9 +396,13 @@ static int vidioc_querycap(struct file *file, void *priv, { strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT - | V4L2_CAP_STREAMING; - + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; return 0; } diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 7e32331b60fb..f1220d3d4970 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -2014,7 +2014,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return -EINVAL; switch (sel->target) { - case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_BOUNDS: sel->r.left = 0; sel->r.top = 0; sel->r.width = INT_MAX; @@ -2024,7 +2024,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, ccdc_try_crop(ccdc, format, &sel->r); break; - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: + case V4L2_SEL_TGT_CROP: sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); break; @@ -2052,7 +2052,7 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL || + if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != CCDC_PAD_SOURCE_OF) return -EINVAL; @@ -2064,7 +2064,7 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * pad. If the KEEP_CONFIG flag is set, just return the current crop * rectangle. */ - if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) { + if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); return 0; } diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index 8a4935ecc655..53f5a703e31a 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -888,12 +888,12 @@ static const struct preview_update update_attrs[] = { preview_config_contrast, NULL, offsetof(struct prev_params, contrast), - 0, true, + 0, 0, true, }, /* OMAP3ISP_PREV_BRIGHTNESS */ { preview_config_brightness, NULL, offsetof(struct prev_params, brightness), - 0, true, + 0, 0, true, }, }; @@ -1102,7 +1102,7 @@ static void preview_config_input_size(struct isp_prev_device *prev, u32 active) unsigned int elv = prev->crop.top + prev->crop.height - 1; u32 features; - if (format->code == V4L2_MBUS_FMT_Y10_1X10) { + if (format->code != V4L2_MBUS_FMT_Y10_1X10) { sph -= 2; eph += 2; slv -= 2; @@ -1949,7 +1949,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, return -EINVAL; switch (sel->target) { - case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_BOUNDS: sel->r.left = 0; sel->r.top = 0; sel->r.width = INT_MAX; @@ -1960,7 +1960,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, preview_try_crop(prev, format, &sel->r); break; - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: + case V4L2_SEL_TGT_CROP: sel->r = *__preview_get_crop(prev, fh, sel->which); break; @@ -1988,7 +1988,7 @@ static int preview_set_selection(struct v4l2_subdev *sd, struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL || + if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != PREV_PAD_SINK) return -EINVAL; @@ -2000,7 +2000,7 @@ static int preview_set_selection(struct v4l2_subdev *sd, * pad. If the KEEP_CONFIG flag is set, just return the current crop * rectangle. */ - if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) { + if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { sel->r = *__preview_get_crop(prev, fh, sel->which); return 0; } diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 14041c9c8643..ae17d917f77b 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1249,7 +1249,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, sel->which); switch (sel->target) { - case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_BOUNDS: sel->r.left = 0; sel->r.top = 0; sel->r.width = INT_MAX; @@ -1259,7 +1259,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, resizer_calc_ratios(res, &sel->r, format_source, &ratio); break; - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: + case V4L2_SEL_TGT_CROP: sel->r = *__resizer_get_crop(res, fh, sel->which); resizer_calc_ratios(res, &sel->r, format_source, &ratio); break; @@ -1293,7 +1293,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format_sink, *format_source; struct resizer_ratio ratio; - if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL || + if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != RESZ_PAD_SINK) return -EINVAL; diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 3c2c5d3bcc6b..7c44d1fe3c87 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c @@ -837,10 +837,8 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd, if (!priv->win) { u32 width = W_SVGA, height = H_SVGA; - int ret = ov2640_set_params(client, &width, &height, - V4L2_MBUS_FMT_UYVY8_2X8); - if (ret < 0) - return ret; + priv->win = ov2640_select_win(&width, &height); + priv->cfmt_code = V4L2_MBUS_FMT_UYVY8_2X8; } mf->width = priv->win->width; diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 74e77d327ed8..6d79b89b8603 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -880,15 +880,11 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) static int ov772x_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); if (!priv->win || !priv->cfmt) { - u32 width = VGA_WIDTH, height = VGA_HEIGHT; - int ret = ov772x_set_params(client, &width, &height, - V4L2_MBUS_FMT_YUYV8_2X8); - if (ret < 0) - return ret; + priv->cfmt = &ov772x_cfmts[0]; + priv->win = ov772x_select_win(VGA_WIDTH, VGA_HEIGHT); } mf->width = priv->win->width; diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 23412debb36b..9ed4ba4236c4 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -605,6 +605,7 @@ static int ov9640_video_probe(struct i2c_client *client) devname = "ov9640"; priv->model = V4L2_IDENT_OV9640; priv->revision = 2; + break; case OV9640_V3: devname = "ov9640"; priv->model = V4L2_IDENT_OV9640; diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index c370c2d87c17..77f9c92186f4 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -26,10 +26,10 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/slab.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/mutex.h> -#include <linux/slab.h> #include <linux/uaccess.h> #include <linux/isa.h> #include <asm/io.h> diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index f9b6001e1dd7..25e412ecad2c 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -1,7 +1,6 @@ config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" depends on VIDEO_V4L2 && I2C - depends on VIDEO_MEDIA # Avoids pvrusb = Y / DVB = M select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 7bddfaeeafc3..f344aed32a93 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -226,13 +226,11 @@ static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) struct v4l2_input tmp; unsigned int cnt; int val; - int ret; cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT); memset(&tmp, 0, sizeof(tmp)); tmp.index = vi->index; - ret = 0; if (vi->index >= fh->input_cnt) return -EINVAL; val = fh->input_map[vi->index]; @@ -556,9 +554,7 @@ static int pvr2_queryctrl(struct file *file, void *priv, struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; int val; - int ret; - ret = 0; if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) { cptr = pvr2_hdw_get_ctrl_nextv4l( hdw, (vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL)); @@ -705,11 +701,9 @@ static int pvr2_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_control *ctrl; struct pvr2_ctrl *pctl; unsigned int idx; - int ret; /* For the moment just validate that the requested control actually exists. */ - ret = 0; for (idx = 0; idx < ctls->count; idx++) { ctrl = ctls->controls + idx; pctl = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id); @@ -770,12 +764,10 @@ static int pvr2_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; - struct v4l2_cropcap cap; int ret; if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = pvr2_ctrl_set_value( pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), crop->c.left); @@ -965,7 +957,7 @@ static long pvr2_v4l2_ioctl(struct file *file, long ret = -EINVAL; if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) - v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), cmd); + v4l_printk_ioctl(pvr2_hdw_get_driver_name(hdw), cmd); if (!pvr2_hdw_dev_ok(hdw)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, @@ -998,7 +990,7 @@ static long pvr2_v4l2_ioctl(struct file *file, pvr2_trace(PVR2_TRACE_V4LIOCTL, "pvr2_v4l2_do_ioctl failure, ret=%ld" " command was:", ret); - v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), + v4l_printk_ioctl(pvr2_hdw_get_driver_name(hdw), cmd); } } diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index ec4e2ef54e65..de7c7ba99ef4 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -136,19 +136,13 @@ static int leds[2] = { 100, 0 }; /***/ -static int pwc_video_close(struct file *file); -static ssize_t pwc_video_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); -static unsigned int pwc_video_poll(struct file *file, poll_table *wait); -static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); - static const struct v4l2_file_operations pwc_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .release = pwc_video_close, - .read = pwc_video_read, - .poll = pwc_video_poll, - .mmap = pwc_video_mmap, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; static struct video_device pwc_template = { @@ -562,17 +556,6 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type) /***************************************************************************/ /* Video4Linux functions */ -int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file) -{ - if (pdev->capt_file != NULL && - pdev->capt_file != file) - return -EBUSY; - - pdev->capt_file = file; - - return 0; -} - static void pwc_video_release(struct v4l2_device *v) { struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); @@ -583,113 +566,6 @@ static void pwc_video_release(struct v4l2_device *v) kfree(pdev); } -static int pwc_video_close(struct file *file) -{ - struct pwc_device *pdev = video_drvdata(file); - - /* - * If we're still streaming vb2_queue_release will call stream_stop - * so we must take both the v4l2_lock and the vb_queue_lock. - */ - if (mutex_lock_interruptible(&pdev->v4l2_lock)) - return -ERESTARTSYS; - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) { - mutex_unlock(&pdev->v4l2_lock); - return -ERESTARTSYS; - } - - if (pdev->capt_file == file) { - vb2_queue_release(&pdev->vb_queue); - pdev->capt_file = NULL; - } - - mutex_unlock(&pdev->vb_queue_lock); - mutex_unlock(&pdev->v4l2_lock); - - return v4l2_fh_release(file); -} - -static ssize_t pwc_video_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct pwc_device *pdev = video_drvdata(file); - int lock_v4l2 = 0; - ssize_t ret; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret) - goto out; - - /* stream_start will get called so we must take the v4l2_lock */ - if (pdev->vb_queue.fileio == NULL) - lock_v4l2 = 1; - - /* Use try_lock, since we're taking the locks in the *wrong* order! */ - if (lock_v4l2 && !mutex_trylock(&pdev->v4l2_lock)) { - ret = -ERESTARTSYS; - goto out; - } - ret = vb2_read(&pdev->vb_queue, buf, count, ppos, - file->f_flags & O_NONBLOCK); - if (lock_v4l2) - mutex_unlock(&pdev->v4l2_lock); -out: - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - -static unsigned int pwc_video_poll(struct file *file, poll_table *wait) -{ - struct pwc_device *pdev = video_drvdata(file); - struct vb2_queue *q = &pdev->vb_queue; - unsigned long req_events = poll_requested_events(wait); - unsigned int ret = POLL_ERR; - int lock_v4l2 = 0; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return POLL_ERR; - - /* Will this start fileio and thus call start_stream? */ - if ((req_events & (POLLIN | POLLRDNORM)) && - q->num_buffers == 0 && !q->streaming && q->fileio == NULL) { - if (pwc_test_n_set_capt_file(pdev, file)) - goto out; - lock_v4l2 = 1; - } - - /* Use try_lock, since we're taking the locks in the *wrong* order! */ - if (lock_v4l2 && !mutex_trylock(&pdev->v4l2_lock)) - goto out; - ret = vb2_poll(&pdev->vb_queue, file, wait); - if (lock_v4l2) - mutex_unlock(&pdev->v4l2_lock); - -out: - if (!pdev->udev) - ret |= POLLHUP; - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - -static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret == 0) - ret = vb2_mmap(&pdev->vb_queue, vma); - - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - /***************************************************************************/ /* Videobuf2 operations */ @@ -782,6 +658,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) if (!pdev->udev) return -ENODEV; + if (mutex_lock_interruptible(&pdev->v4l2_lock)) + return -ERESTARTSYS; /* Turn on camera and set LEDS on */ pwc_camera_power(pdev, 1); pwc_set_leds(pdev, leds[0], leds[1]); @@ -794,6 +672,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) /* And cleanup any queued bufs!! */ pwc_cleanup_queued_bufs(pdev); } + mutex_unlock(&pdev->v4l2_lock); return r; } @@ -802,6 +681,8 @@ static int stop_streaming(struct vb2_queue *vq) { struct pwc_device *pdev = vb2_get_drv_priv(vq); + if (mutex_lock_interruptible(&pdev->v4l2_lock)) + return -ERESTARTSYS; if (pdev->udev) { pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); @@ -809,22 +690,11 @@ static int stop_streaming(struct vb2_queue *vq) } pwc_cleanup_queued_bufs(pdev); + mutex_unlock(&pdev->v4l2_lock); return 0; } -static void wait_prepare(struct vb2_queue *vq) -{ - struct pwc_device *pdev = vb2_get_drv_priv(vq); - mutex_unlock(&pdev->vb_queue_lock); -} - -static void wait_finish(struct vb2_queue *vq) -{ - struct pwc_device *pdev = vb2_get_drv_priv(vq); - mutex_lock(&pdev->vb_queue_lock); -} - static struct vb2_ops pwc_vb_queue_ops = { .queue_setup = queue_setup, .buf_init = buffer_init, @@ -834,8 +704,8 @@ static struct vb2_ops pwc_vb_queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = wait_prepare, - .wait_finish = wait_finish, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /***************************************************************************/ @@ -1136,6 +1006,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id /* Init video_device structure */ memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); strcpy(pdev->vdev.name, name); + pdev->vdev.queue = &pdev->vb_queue; + pdev->vdev.queue->lock = &pdev->vb_queue_lock; set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags); video_set_drvdata(&pdev->vdev, pdev); @@ -1190,15 +1062,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vdev.v4l2_dev = &pdev->v4l2_dev; pdev->vdev.lock = &pdev->v4l2_lock; - /* - * Don't take v4l2_lock for these ioctls. This improves latency if - * v4l2_lock is taken for a long time, e.g. when changing a control - * value, and a new frame is ready to be dequeued. - */ - v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_DQBUF); - v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_QBUF); - v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_QUERYBUF); - rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1); if (rc < 0) { PWC_ERROR("Failed to register as video device (%d).\n", rc); @@ -1253,20 +1116,18 @@ static void usb_pwc_disconnect(struct usb_interface *intf) struct v4l2_device *v = usb_get_intfdata(intf); struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); - mutex_lock(&pdev->v4l2_lock); - mutex_lock(&pdev->vb_queue_lock); + mutex_lock(&pdev->v4l2_lock); /* No need to keep the urbs around after disconnection */ if (pdev->vb_queue.streaming) pwc_isoc_cleanup(pdev); pdev->udev = NULL; pwc_cleanup_queued_bufs(pdev); - mutex_unlock(&pdev->vb_queue_lock); v4l2_device_disconnect(&pdev->v4l2_dev); video_unregister_device(&pdev->vdev); - mutex_unlock(&pdev->v4l2_lock); + mutex_unlock(pdev->vb_queue.lock); #ifdef CONFIG_USB_PWC_INPUT_EVDEV if (pdev->button_dev) diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index c691e29cc36e..545e9bbdeede 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -405,6 +405,7 @@ static void pwc_vidioc_fill_fmt(struct v4l2_format *f, f->fmt.pix.pixelformat = pixfmt; f->fmt.pix.bytesperline = f->fmt.pix.width; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.width * 3 / 2; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() " "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n", f->fmt.pix.width, @@ -468,17 +469,8 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) if (ret < 0) return ret; - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret) - goto leave; - - if (pdev->vb_queue.streaming) { - ret = -EBUSY; - goto leave; - } + if (vb2_is_busy(&pdev->vb_queue)) + return -EBUSY; pixelformat = f->fmt.pix.pixelformat; @@ -496,8 +488,6 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret); pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt); -leave: - mutex_unlock(&pdev->vb_queue_lock); return ret; } @@ -508,10 +498,9 @@ static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap strcpy(cap->driver, PWC_NAME); strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card)); usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -520,7 +509,8 @@ static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i) if (i->index) /* Only one INPUT is supported */ return -EINVAL; - strcpy(i->name, "usb"); + strlcpy(i->name, "Camera", sizeof(i->name)); + i->type = V4L2_INPUT_TYPE_CAMERA; return 0; } @@ -933,104 +923,6 @@ static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format * return pwc_vidioc_try_fmt(pdev, f); } -static int pwc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *rb) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret == 0) - ret = vb2_reqbufs(&pdev->vb_queue, rb); - - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - -static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret == 0) - ret = vb2_querybuf(&pdev->vb_queue, buf); - - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - -static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret == 0) - ret = vb2_qbuf(&pdev->vb_queue, buf); - - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - -static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret == 0) - ret = vb2_dqbuf(&pdev->vb_queue, buf, - file->f_flags & O_NONBLOCK); - - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - -static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret == 0) - ret = vb2_streamon(&pdev->vb_queue, i); - - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - -static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) -{ - struct pwc_device *pdev = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; - - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret == 0) - ret = vb2_streamoff(&pdev->vb_queue, i); - - mutex_unlock(&pdev->vb_queue_lock); - return ret; -} - static int pwc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { @@ -1112,32 +1004,27 @@ static int pwc_s_parm(struct file *file, void *fh, int compression = 0; int ret, fps; - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - parm->parm.capture.timeperframe.numerator == 0) + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - fps = parm->parm.capture.timeperframe.denominator / - parm->parm.capture.timeperframe.numerator; - - if (mutex_lock_interruptible(&pdev->vb_queue_lock)) - return -ERESTARTSYS; + /* If timeperframe == 0, then reset the framerate to the nominal value. + We pick a high framerate here, and let pwc_set_video_mode() figure + out the best match. */ + if (parm->parm.capture.timeperframe.numerator == 0 || + parm->parm.capture.timeperframe.denominator == 0) + fps = 30; + else + fps = parm->parm.capture.timeperframe.denominator / + parm->parm.capture.timeperframe.numerator; - ret = pwc_test_n_set_capt_file(pdev, file); - if (ret) - goto leave; - - if (pdev->vb_queue.streaming) { - ret = -EBUSY; - goto leave; - } + if (vb2_is_busy(&pdev->vb_queue)) + return -EBUSY; ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt, fps, &compression, 0); pwc_g_parm(file, fh, parm); -leave: - mutex_unlock(&pdev->vb_queue_lock); return ret; } @@ -1150,12 +1037,12 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = { .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap, .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap, .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap, - .vidioc_reqbufs = pwc_reqbufs, - .vidioc_querybuf = pwc_querybuf, - .vidioc_qbuf = pwc_qbuf, - .vidioc_dqbuf = pwc_dqbuf, - .vidioc_streamon = pwc_streamon, - .vidioc_streamoff = pwc_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_enum_framesizes = pwc_enum_framesizes, .vidioc_enum_frameintervals = pwc_enum_frameintervals, diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index d6b5b216b9d6..7a6a0d39c2c6 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -239,7 +239,6 @@ struct pwc_device int features; /* feature bits */ /*** Video data ***/ - struct file *capt_file; /* file doing video capture */ int vendpoint; /* video isoc endpoint */ int vcinterface; /* video control interface */ int valternate; /* alternate interface needed */ @@ -355,8 +354,6 @@ struct pwc_device extern int pwc_trace; #endif -int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file); - /** Functions in pwc-misc.c */ /* sizes in pixels */ extern const int pwc_image_sizes[PSZ_MAX][2]; diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 01c2179f0520..95007dda0c93 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -2686,3 +2686,4 @@ MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver"); MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)"); MODULE_LICENSE("GPL"); MODULE_VERSION(S2255_VERSION); +MODULE_FIRMWARE(FIRMWARE_FILE_NAME); diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 354574591908..8e413dd3c0b0 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -350,7 +350,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, if (pixm) sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); else - sizes[i] = size; + sizes[i] = max_t(u32, size, frame->payload[i]); + allocators[i] = ctx->fimc_dev->alloc_ctx; } @@ -479,46 +480,59 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc); static int fimc_capture_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); - int ret = v4l2_fh_open(file); - - if (ret) - return ret; + int ret = -EBUSY; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); - /* Return if the corresponding video mem2mem node is already opened. */ + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + if (fimc_m2m_active(fimc)) - return -EBUSY; + goto unlock; set_bit(ST_CAPT_BUSY, &fimc->state); - pm_runtime_get_sync(&fimc->pdev->dev); + ret = pm_runtime_get_sync(&fimc->pdev->dev); + if (ret < 0) + goto unlock; + + ret = v4l2_fh_open(file); + if (ret) { + pm_runtime_put(&fimc->pdev->dev); + goto unlock; + } if (++fimc->vid_cap.refcnt == 1) { ret = fimc_pipeline_initialize(&fimc->pipeline, - &fimc->vid_cap.vfd->entity, true); + &fimc->vid_cap.vfd->entity, true); + + if (!ret && !fimc->vid_cap.user_subdev_api) + ret = fimc_capture_set_default_format(fimc); + + if (!ret) + ret = fimc_capture_ctrls_create(fimc); + if (ret < 0) { - dev_err(&fimc->pdev->dev, - "Video pipeline initialization failed\n"); + clear_bit(ST_CAPT_BUSY, &fimc->state); pm_runtime_put_sync(&fimc->pdev->dev); fimc->vid_cap.refcnt--; v4l2_fh_release(file); - clear_bit(ST_CAPT_BUSY, &fimc->state); - return ret; } - ret = fimc_capture_ctrls_create(fimc); - - if (!ret && !fimc->vid_cap.user_subdev_api) - ret = fimc_capture_set_default_format(fimc); } +unlock: + mutex_unlock(&fimc->lock); return ret; } static int fimc_capture_close(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); + int ret; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + if (--fimc->vid_cap.refcnt == 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); fimc_stop_capture(fimc, false); @@ -532,22 +546,40 @@ static int fimc_capture_close(struct file *file) vb2_queue_release(&fimc->vid_cap.vbq); fimc_ctrls_delete(fimc->vid_cap.ctx); } - return v4l2_fh_release(file); + + ret = v4l2_fh_release(file); + + mutex_unlock(&fimc->lock); + return ret; } static unsigned int fimc_capture_poll(struct file *file, struct poll_table_struct *wait) { struct fimc_dev *fimc = video_drvdata(file); + int ret; - return vb2_poll(&fimc->vid_cap.vbq, file, wait); + if (mutex_lock_interruptible(&fimc->lock)) + return POLL_ERR; + + ret = vb2_poll(&fimc->vid_cap.vbq, file, wait); + mutex_unlock(&fimc->lock); + + return ret; } static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) { struct fimc_dev *fimc = video_drvdata(file); + int ret; - return vb2_mmap(&fimc->vid_cap.vbq, vma); + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + + ret = vb2_mmap(&fimc->vid_cap.vbq, vma); + mutex_unlock(&fimc->lock); + + return ret; } static const struct v4l2_file_operations fimc_capture_fops = { @@ -655,7 +687,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, r->left = r->top = 0; return; } - if (target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { + if (target == V4L2_SEL_TGT_COMPOSE) { if (ctx->rotation != 90 && ctx->rotation != 270) align_h = 1; max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3)); @@ -682,7 +714,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, rotate ? sink->f_height : sink->f_width); max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height); - if (target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { + if (target == V4L2_SEL_TGT_COMPOSE) { min_w = min_t(u32, max_w, sink->f_width / max_sc_h); min_h = min_t(u32, max_h, sink->f_height / max_sc_v); if (rotate) { @@ -818,9 +850,6 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx = fimc->vid_cap.ctx; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - return fimc_fill_format(&ctx->d_frame, f); } @@ -833,9 +862,6 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct v4l2_mbus_framefmt mf; struct fimc_fmt *ffmt = NULL; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, @@ -887,8 +913,6 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) struct fimc_fmt *s_fmt = NULL; int ret, i; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; if (vb2_is_busy(&fimc->vid_cap.vbq)) return -EBUSY; @@ -924,10 +948,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) pix->width = mf->width; pix->height = mf->height; } + fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); for (i = 0; i < ff->fmt->colplanes; i++) - ff->payload[i] = - (pix->width * pix->height * ff->fmt->depth[i]) / 8; + ff->payload[i] = pix->plane_fmt[i].sizeimage; set_frame_bounds(ff, pix->width, pix->height); /* Reset the composition rectangle if not yet configured */ @@ -1045,18 +1069,22 @@ static int fimc_cap_streamon(struct file *file, void *priv, { struct fimc_dev *fimc = video_drvdata(file); struct fimc_pipeline *p = &fimc->pipeline; + struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR]; int ret; if (fimc_capture_active(fimc)) return -EBUSY; - media_entity_pipeline_start(&p->subdevs[IDX_SENSOR]->entity, - p->m_pipeline); + ret = media_entity_pipeline_start(&sd->entity, p->m_pipeline); + if (ret < 0) + return ret; if (fimc->vid_cap.user_subdev_api) { ret = fimc_pipeline_validate(fimc); - if (ret) + if (ret < 0) { + media_entity_pipeline_stop(&sd->entity); return ret; + } } return vb2_streamon(&fimc->vid_cap.vbq, type); } @@ -1147,9 +1175,9 @@ static int fimc_cap_g_selection(struct file *file, void *fh, s->r.height = f->o_height; return 0; - case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE: f = &ctx->d_frame; - case V4L2_SEL_TGT_CROP_ACTIVE: + case V4L2_SEL_TGT_CROP: s->r.left = f->offs_h; s->r.top = f->offs_v; s->r.width = f->width; @@ -1161,7 +1189,7 @@ static int fimc_cap_g_selection(struct file *file, void *fh, } /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ -int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) +static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) { if (a->left < b->left || a->top < b->top) return 0; @@ -1185,9 +1213,9 @@ static int fimc_cap_s_selection(struct file *file, void *fh, if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) + if (s->target == V4L2_SEL_TGT_COMPOSE) f = &ctx->d_frame; - else if (s->target == V4L2_SEL_TGT_CROP_ACTIVE) + else if (s->target == V4L2_SEL_TGT_CROP) f = &ctx->s_frame; else return -EINVAL; @@ -1429,9 +1457,9 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, mutex_lock(&fimc->lock); switch (sel->target) { - case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: f = &ctx->d_frame; - case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_BOUNDS: r->width = f->o_width; r->height = f->o_height; r->left = 0; @@ -1439,10 +1467,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, mutex_unlock(&fimc->lock); return 0; - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: + case V4L2_SEL_TGT_CROP: try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); break; - case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL: + case V4L2_SEL_TGT_COMPOSE: try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); f = &ctx->d_frame; break; @@ -1483,12 +1511,12 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd, return -EINVAL; mutex_lock(&fimc->lock); - fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP_ACTIVE); + fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP); switch (sel->target) { - case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: f = &ctx->d_frame; - case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_BOUNDS: r->width = f->o_width; r->height = f->o_height; r->left = 0; @@ -1496,10 +1524,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd, mutex_unlock(&fimc->lock); return 0; - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: + case V4L2_SEL_TGT_CROP: try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); break; - case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL: + case V4L2_SEL_TGT_COMPOSE: try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); f = &ctx->d_frame; break; @@ -1515,7 +1543,7 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd, set_frame_crop(f, r->left, r->top, r->width, r->height); set_bit(ST_CAPT_APPLY_CFG, &fimc->state); spin_unlock_irqrestore(&fimc->slock, flags); - if (sel->target == V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL) + if (sel->target == V4L2_SEL_TGT_COMPOSE) ctx->state |= FIMC_COMPOSE; } @@ -1590,10 +1618,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, vfd->minor = -1; vfd->release = video_device_release; vfd->lock = &fimc->lock; - /* Locking in file operations other than ioctl should be done - by the driver, not the V4L2 core. - This driver needs auditing so that this flag can be removed. */ - set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags); + video_set_drvdata(vfd, fimc); vid_cap = &fimc->vid_cap; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 92fc5a20fb76..1a445404e73d 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -153,7 +153,7 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr", + .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", .fourcc = V4L2_PIX_FMT_NV12M, .color = FIMC_FMT_YCBCR420, .depth = { 8, 4 }, @@ -161,7 +161,7 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 2, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr", + .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr", .fourcc = V4L2_PIX_FMT_YUV420M, .color = FIMC_FMT_YCBCR420, .depth = { 8, 2, 2 }, @@ -169,7 +169,7 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 3, .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled", + .name = "YUV 4:2:0 non-contig. 2p, tiled", .fourcc = V4L2_PIX_FMT_NV12MT, .color = FIMC_FMT_YCBCR420, .depth = { 8, 4 }, @@ -463,7 +463,7 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v); } -int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx) +static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx) { struct fimc_effect *effect = &ctx->effect; @@ -641,7 +641,7 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) if (!ctrls->ready) return; - mutex_lock(&ctrls->handler.lock); + mutex_lock(ctrls->handler.lock); v4l2_ctrl_activate(ctrls->rotate, active); v4l2_ctrl_activate(ctrls->hflip, active); v4l2_ctrl_activate(ctrls->vflip, active); @@ -660,7 +660,7 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) ctx->hflip = 0; ctx->vflip = 0; } - mutex_unlock(&ctrls->handler.lock); + mutex_unlock(ctrls->handler.lock); } /* Update maximum value of the alpha color control */ @@ -741,8 +741,8 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, pix->width = width; for (i = 0; i < pix->num_planes; ++i) { - u32 bpl = pix->plane_fmt[i].bytesperline; - u32 *sizeimage = &pix->plane_fmt[i].sizeimage; + struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i]; + u32 bpl = plane_fmt->bytesperline; if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) bpl = pix->width; /* Planar */ @@ -754,8 +754,9 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, if (i == 0) /* Same bytesperline for each plane. */ bytesperline = bpl; - pix->plane_fmt[i].bytesperline = bytesperline; - *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8; + plane_fmt->bytesperline = bytesperline; + plane_fmt->sizeimage = max((pix->width * pix->height * + fmt->depth[i]) / 8, plane_fmt->sizeimage); } } diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 95b27ae5cf27..808ccc621846 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -27,9 +27,6 @@ #include <media/v4l2-mediabus.h> #include <media/s5p_fimc.h> -#define err(fmt, args...) \ - printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args) - #define dbg(fmt, args...) \ pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args) diff --git a/drivers/media/video/s5p-fimc/fimc-lite-reg.c b/drivers/media/video/s5p-fimc/fimc-lite-reg.c index 419adfb7cdf9..f996e94873f6 100644 --- a/drivers/media/video/s5p-fimc/fimc-lite-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-lite-reg.c @@ -215,7 +215,7 @@ void flite_hw_set_camera_bus(struct fimc_lite *dev, flite_hw_set_camera_port(dev, s_info->mux_id); } -void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) +static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) { static const u32 pixcode[4][2] = { { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR }, diff --git a/drivers/media/video/s5p-fimc/fimc-lite.c b/drivers/media/video/s5p-fimc/fimc-lite.c index 400d701aef04..c5b57e805b68 100644 --- a/drivers/media/video/s5p-fimc/fimc-lite.c +++ b/drivers/media/video/s5p-fimc/fimc-lite.c @@ -451,34 +451,44 @@ static void fimc_lite_clear_event_counters(struct fimc_lite *fimc) static int fimc_lite_open(struct file *file) { struct fimc_lite *fimc = video_drvdata(file); - int ret = v4l2_fh_open(file); + int ret; - if (ret) - return ret; + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; set_bit(ST_FLITE_IN_USE, &fimc->state); - pm_runtime_get_sync(&fimc->pdev->dev); + ret = pm_runtime_get_sync(&fimc->pdev->dev); + if (ret < 0) + goto done; - if (++fimc->ref_count != 1 || fimc->out_path != FIMC_IO_DMA) - return ret; + ret = v4l2_fh_open(file); + if (ret < 0) + goto done; - ret = fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity, - true); - if (ret < 0) { - v4l2_err(fimc->vfd, "Video pipeline initialization failed\n"); - pm_runtime_put_sync(&fimc->pdev->dev); - fimc->ref_count--; - v4l2_fh_release(file); - clear_bit(ST_FLITE_IN_USE, &fimc->state); - } + if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) { + ret = fimc_pipeline_initialize(&fimc->pipeline, + &fimc->vfd->entity, true); + if (ret < 0) { + pm_runtime_put_sync(&fimc->pdev->dev); + fimc->ref_count--; + v4l2_fh_release(file); + clear_bit(ST_FLITE_IN_USE, &fimc->state); + } - fimc_lite_clear_event_counters(fimc); + fimc_lite_clear_event_counters(fimc); + } +done: + mutex_unlock(&fimc->lock); return ret; } static int fimc_lite_close(struct file *file) { struct fimc_lite *fimc = video_drvdata(file); + int ret; + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) { clear_bit(ST_FLITE_IN_USE, &fimc->state); @@ -492,20 +502,39 @@ static int fimc_lite_close(struct file *file) if (fimc->ref_count == 0) vb2_queue_release(&fimc->vb_queue); - return v4l2_fh_release(file); + ret = v4l2_fh_release(file); + + mutex_unlock(&fimc->lock); + return ret; } static unsigned int fimc_lite_poll(struct file *file, struct poll_table_struct *wait) { struct fimc_lite *fimc = video_drvdata(file); - return vb2_poll(&fimc->vb_queue, file, wait); + int ret; + + if (mutex_lock_interruptible(&fimc->lock)) + return POLL_ERR; + + ret = vb2_poll(&fimc->vb_queue, file, wait); + mutex_unlock(&fimc->lock); + + return ret; } static int fimc_lite_mmap(struct file *file, struct vm_area_struct *vma) { struct fimc_lite *fimc = video_drvdata(file); - return vb2_mmap(&fimc->vb_queue, vma); + int ret; + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + + ret = vb2_mmap(&fimc->vb_queue, vma); + mutex_unlock(&fimc->lock); + + return ret; } static const struct v4l2_file_operations fimc_lite_fops = { @@ -762,7 +791,9 @@ static int fimc_lite_streamon(struct file *file, void *priv, if (fimc_lite_active(fimc)) return -EBUSY; - media_entity_pipeline_start(&sensor->entity, p->m_pipeline); + ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline); + if (ret < 0) + return ret; ret = fimc_pipeline_validate(fimc); if (ret) { @@ -871,7 +902,7 @@ static int fimc_lite_g_selection(struct file *file, void *fh, sel->r.height = f->f_height; return 0; - case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE: sel->r = f->rect; return 0; } @@ -888,7 +919,7 @@ static int fimc_lite_s_selection(struct file *file, void *fh, unsigned long flags; if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || - sel->target != V4L2_SEL_TGT_COMPOSE_ACTIVE) + sel->target != V4L2_SEL_TGT_COMPOSE) return -EINVAL; fimc_lite_try_compose(fimc, &rect); @@ -1086,9 +1117,9 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, struct fimc_lite *fimc = v4l2_get_subdevdata(sd); struct flite_frame *f = &fimc->inp_frame; - if ((sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL && - sel->target != V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS) || - sel->pad != FLITE_SD_PAD_SINK) + if ((sel->target != V4L2_SEL_TGT_CROP && + sel->target != V4L2_SEL_TGT_CROP_BOUNDS) || + sel->pad != FLITE_SD_PAD_SINK) return -EINVAL; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { @@ -1097,7 +1128,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, } mutex_lock(&fimc->lock); - if (sel->target == V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL) { + if (sel->target == V4L2_SEL_TGT_CROP) { sel->r = f->rect; } else { sel->r.left = 0; @@ -1122,8 +1153,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, struct flite_frame *f = &fimc->inp_frame; int ret = 0; - if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL || - sel->pad != FLITE_SD_PAD_SINK) + if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != FLITE_SD_PAD_SINK) return -EINVAL; mutex_lock(&fimc->lock); @@ -1508,7 +1538,7 @@ static int fimc_lite_suspend(struct device *dev) return 0; ret = fimc_lite_stop_capture(fimc, suspend); - if (ret) + if (ret < 0 || !fimc_lite_active(fimc)) return ret; return fimc_pipeline_shutdown(&fimc->pipeline); diff --git a/drivers/media/video/s5p-fimc/fimc-m2m.c b/drivers/media/video/s5p-fimc/fimc-m2m.c index 4c58e0570962..c587011d80ef 100644 --- a/drivers/media/video/s5p-fimc/fimc-m2m.c +++ b/drivers/media/video/s5p-fimc/fimc-m2m.c @@ -259,7 +259,12 @@ static int fimc_m2m_querycap(struct file *file, void *fh, strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; - cap->capabilities = V4L2_CAP_STREAMING | + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; return 0; @@ -642,21 +647,25 @@ static int fimc_m2m_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx; - int ret; + int ret = -EBUSY; dbg("pid: %d, state: 0x%lx, refcnt: %d", task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt); + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; /* * Return if the corresponding video capture node * is already opened. */ if (fimc->vid_cap.refcnt > 0) - return -EBUSY; + goto unlock; ctx = kzalloc(sizeof *ctx, GFP_KERNEL); - if (!ctx) - return -ENOMEM; + if (!ctx) { + ret = -ENOMEM; + goto unlock; + } v4l2_fh_init(&ctx->fh, fimc->m2m.vfd); ctx->fimc_dev = fimc; @@ -687,6 +696,8 @@ static int fimc_m2m_open(struct file *file) if (fimc->m2m.refcnt++ == 0) set_bit(ST_M2M_RUN, &fimc->state); + + mutex_unlock(&fimc->lock); return 0; error_c: @@ -695,6 +706,8 @@ error_fh: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); kfree(ctx); +unlock: + mutex_unlock(&fimc->lock); return ret; } @@ -706,6 +719,9 @@ static int fimc_m2m_release(struct file *file) dbg("pid: %d, state: 0x%lx, refcnt= %d", task_pid_nr(current), fimc->state, fimc->m2m.refcnt); + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + v4l2_m2m_ctx_release(ctx->m2m_ctx); fimc_ctrls_delete(ctx); v4l2_fh_del(&ctx->fh); @@ -714,6 +730,8 @@ static int fimc_m2m_release(struct file *file) if (--fimc->m2m.refcnt <= 0) clear_bit(ST_M2M_RUN, &fimc->state); kfree(ctx); + + mutex_unlock(&fimc->lock); return 0; } @@ -721,16 +739,32 @@ static unsigned int fimc_m2m_poll(struct file *file, struct poll_table_struct *wait) { struct fimc_ctx *ctx = fh_to_ctx(file->private_data); + struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + + ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); + mutex_unlock(&fimc->lock); - return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); + return ret; } static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) { struct fimc_ctx *ctx = fh_to_ctx(file->private_data); + struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; - return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); + ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); + mutex_unlock(&fimc->lock); + + return ret; } static const struct v4l2_file_operations fimc_m2m_fops = { @@ -772,10 +806,6 @@ int fimc_register_m2m_device(struct fimc_dev *fimc, vfd->minor = -1; vfd->release = video_device_release; vfd->lock = &fimc->lock; - /* Locking in file operations other than ioctl should be done - by the driver, not the V4L2 core. - This driver needs auditing so that this flag can be removed. */ - set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); video_set_drvdata(vfd, fimc); diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index 6753c45631b8..e65bb283fd8a 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -180,7 +180,7 @@ EXPORT_SYMBOL_GPL(fimc_pipeline_initialize); * sensor clock. * Called with the graph mutex held. */ -int __fimc_pipeline_shutdown(struct fimc_pipeline *p) +static int __fimc_pipeline_shutdown(struct fimc_pipeline *p) { int ret = 0; @@ -193,9 +193,13 @@ int __fimc_pipeline_shutdown(struct fimc_pipeline *p) int fimc_pipeline_shutdown(struct fimc_pipeline *p) { - struct media_entity *me = &p->subdevs[IDX_SENSOR]->entity; + struct media_entity *me; int ret; + if (!p || !p->subdevs[IDX_SENSOR]) + return -EINVAL; + + me = &p->subdevs[IDX_SENSOR]->entity; mutex_lock(&me->parent->graph_mutex); ret = __fimc_pipeline_shutdown(p); mutex_unlock(&me->parent->graph_mutex); @@ -498,12 +502,12 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) * @source: the source entity to create links to all fimc entities from * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null * @pad: the source entity pad index - * @fimc_id: index of the fimc device for which link should be enabled + * @link_mask: bitmask of the fimc devices for which link should be enabled */ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, struct media_entity *source, struct v4l2_subdev *sensor, - int pad, int fimc_id) + int pad, int link_mask) { struct fimc_sensor_info *s_info; struct media_entity *sink; @@ -520,7 +524,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, if (!fmd->fimc[i]->variant->has_cam_if) continue; - flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0; + flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0; sink = &fmd->fimc[i]->vid_cap.subdev.entity; ret = media_entity_create_link(source, pad, sink, @@ -552,7 +556,10 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, if (!fmd->fimc_lite[i]) continue; - flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0; + if (link_mask & (1 << (i + FIMC_MAX_DEVS))) + flags = MEDIA_LNK_FL_ENABLED; + else + flags = 0; sink = &fmd->fimc_lite[i]->subdev.entity; ret = media_entity_create_link(source, pad, sink, @@ -614,9 +621,8 @@ static int fimc_md_create_links(struct fimc_md *fmd) struct s5p_fimc_isp_info *pdata; struct fimc_sensor_info *s_info; struct media_entity *source, *sink; - int i, pad, fimc_id = 0; - int ret = 0; - u32 flags; + int i, pad, fimc_id = 0, ret = 0; + u32 flags, link_mask = 0; for (i = 0; i < fmd->num_sensors; i++) { if (fmd->sensor[i].subdev == NULL) @@ -668,19 +674,20 @@ static int fimc_md_create_links(struct fimc_md *fmd) if (source == NULL) continue; + link_mask = 1 << fimc_id++; ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor, - pad, fimc_id++); + pad, link_mask); } - fimc_id = 0; for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) { if (fmd->csis[i].sd == NULL) continue; source = &fmd->csis[i].sd->entity; pad = CSIS_PAD_SOURCE; + link_mask = 1 << fimc_id++; ret = __fimc_md_create_fimc_sink_links(fmd, source, NULL, - pad, fimc_id++); + pad, link_mask); } /* Create immutable links between each FIMC's subdev and video node */ @@ -734,8 +741,8 @@ static void fimc_md_put_clocks(struct fimc_md *fmd) } static int __fimc_md_set_camclk(struct fimc_md *fmd, - struct fimc_sensor_info *s_info, - bool on) + struct fimc_sensor_info *s_info, + bool on) { struct s5p_fimc_isp_info *pdata = s_info->pdata; struct fimc_camclk_info *camclk; @@ -744,12 +751,10 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL) return -EINVAL; - if (s_info->clk_on == on) - return 0; camclk = &fmd->camclk[pdata->clk_id]; - dbg("camclk %d, f: %lu, clk: %p, on: %d", - pdata->clk_id, pdata->clk_frequency, camclk, on); + dbg("camclk %d, f: %lu, use_count: %d, on: %d", + pdata->clk_id, pdata->clk_frequency, camclk->use_count, on); if (on) { if (camclk->use_count > 0 && @@ -760,11 +765,9 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, clk_set_rate(camclk->clock, pdata->clk_frequency); camclk->frequency = pdata->clk_frequency; ret = clk_enable(camclk->clock); + dbg("Enabled camclk %d: f: %lu", pdata->clk_id, + clk_get_rate(camclk->clock)); } - s_info->clk_on = 1; - dbg("Enabled camclk %d: f: %lu", pdata->clk_id, - clk_get_rate(camclk->clock)); - return ret; } @@ -773,7 +776,6 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, if (--camclk->use_count == 0) { clk_disable(camclk->clock); - s_info->clk_on = 0; dbg("Disabled camclk %d", pdata->clk_id); } return ret; @@ -789,8 +791,6 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, * devices to which sensors can be attached, either directly or through * the MIPI CSI receiver. The clock is allowed here to be used by * multiple sensors concurrently if they use same frequency. - * The per sensor subdev clk_on attribute helps to synchronize accesses - * to the sclk_cam clocks from the video and media device nodes. * This function should only be called when the graph mutex is held. */ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) @@ -1010,7 +1010,7 @@ static struct platform_driver fimc_md_driver = { } }; -int __init fimc_md_init(void) +static int __init fimc_md_init(void) { int ret; @@ -1021,7 +1021,8 @@ int __init fimc_md_init(void) return platform_driver_register(&fimc_md_driver); } -void __exit fimc_md_exit(void) + +static void __exit fimc_md_exit(void) { platform_driver_unregister(&fimc_md_driver); fimc_unregister_driver(); diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.h b/drivers/media/video/s5p-fimc/fimc-mdevice.h index 3b8a3492a176..1f5dbaff5442 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.h +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.h @@ -47,7 +47,6 @@ struct fimc_camclk_info { * @pdata: sensor's atrributes passed as media device's platform data * @subdev: image sensor v4l2 subdev * @host: fimc device the sensor is currently linked to - * @clk_on: sclk_cam clock's state associated with this subdev * * This data structure applies to image sensor and the writeback subdevs. */ @@ -55,7 +54,6 @@ struct fimc_sensor_info { struct s5p_fimc_isp_info *pdata; struct v4l2_subdev *subdev; struct fimc_dev *host; - bool clk_on; }; /** diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 1fc4ce8446f5..0e3eb9ce4f98 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -667,7 +667,8 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB | FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG); - if (cam->bus_type == FIMC_MIPI_CSI2) { + switch (cam->bus_type) { + case FIMC_MIPI_CSI2: cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI; if (cam->mux_id == 0) @@ -683,23 +684,24 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; break; default: - v4l2_err(fimc->vid_cap.vfd, - "Not supported camera pixel format: %d", + v4l2_err(vid_cap->vfd, + "Not supported camera pixel format: %#x\n", vid_cap->mf.code); return -EINVAL; } tmp |= (csis_data_alignment == 32) << 8; writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT); - - } else if (cam->bus_type == FIMC_ITU_601 || - cam->bus_type == FIMC_ITU_656) { + break; + case FIMC_ITU_601...FIMC_ITU_656: if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A; - } else if (cam->bus_type == FIMC_LCD_WB) { + break; + case FIMC_LCD_WB: cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; - } else { - err("invalid camera bus type selected\n"); + break; + default: + v4l2_err(vid_cap->vfd, "Invalid camera bus type selected\n"); return -EINVAL; } writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c index 7c98ee7377ee..7c2200435206 100644 --- a/drivers/media/video/s5p-g2d/g2d.c +++ b/drivers/media/video/s5p-g2d/g2d.c @@ -290,8 +290,13 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1); cap->bus_info[0] = 0; cap->version = KERNEL_VERSION(1, 0, 0); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT - | V4L2_CAP_STREAMING; + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; return 0; } diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c index 28b5225d94f5..813b801238d1 100644 --- a/drivers/media/video/s5p-jpeg/jpeg-core.c +++ b/drivers/media/video/s5p-jpeg/jpeg-core.c @@ -489,9 +489,13 @@ static int s5p_jpeg_querycap(struct file *file, void *priv, sizeof(cap->card)); } cap->bus_info[0] = 0; - cap->capabilities = V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OUTPUT; + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT; return 0; } @@ -824,10 +828,10 @@ static int s5p_jpeg_g_selection(struct file *file, void *priv, /* For JPEG blob active == default == bounds */ switch (s->target) { - case V4L2_SEL_TGT_CROP_ACTIVE: + case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_COMPOSE_DEFAULT: s->r.width = ctx->out_q.w; s->r.height = ctx->out_q.h; @@ -1503,29 +1507,7 @@ static struct platform_driver s5p_jpeg_driver = { }, }; -static int __init -s5p_jpeg_register(void) -{ - int ret; - - pr_info("S5P JPEG V4L2 Driver, (c) 2011 Samsung Electronics\n"); - - ret = platform_driver_register(&s5p_jpeg_driver); - - if (ret) - pr_err("%s: failed to register jpeg driver\n", __func__); - - return ret; -} - -static void __exit -s5p_jpeg_unregister(void) -{ - platform_driver_unregister(&s5p_jpeg_driver); -} - -module_init(s5p_jpeg_register); -module_exit(s5p_jpeg_unregister); +module_platform_driver(s5p_jpeg_driver); MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>"); MODULE_DESCRIPTION("Samsung JPEG codec driver"); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index 4dd32fc8fd82..c5d567f87d77 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -220,8 +220,14 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; cap->version = KERNEL_VERSION(1, 0, 0); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | - V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING; + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE; return 0; } @@ -996,6 +1002,7 @@ int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) for (i = 0; i < NUM_CTRLS; i++) { if (IS_MFC51_PRIV(controls[i].id)) { + memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); cfg.ops = &s5p_mfc_dec_ctrl_ops; cfg.id = controls[i].id; cfg.min = controls[i].minimum; diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index 03d83340e7fb..aa1c244cf66e 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -779,9 +779,14 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; cap->version = KERNEL_VERSION(1, 0, 0); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE - | V4L2_CAP_VIDEO_OUTPUT_MPLANE - | V4L2_CAP_STREAMING; + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE; return 0; } @@ -1773,6 +1778,7 @@ int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx) } for (i = 0; i < NUM_CTRLS; i++) { if (IS_MFC51_PRIV(controls[i].id)) { + memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); cfg.ops = &s5p_mfc_enc_ctrl_ops; cfg.id = controls[i].id; cfg.min = controls[i].minimum; diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index 33fde2a763ec..6c74b05d1f95 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -367,7 +367,7 @@ static int mxr_g_selection(struct file *file, void *fh, return -EINVAL; switch (s->target) { - case V4L2_SEL_TGT_CROP_ACTIVE: + case V4L2_SEL_TGT_CROP: s->r.left = geo->src.x_offset; s->r.top = geo->src.y_offset; s->r.width = geo->src.width; @@ -380,7 +380,7 @@ static int mxr_g_selection(struct file *file, void *fh, s->r.width = geo->src.full_width; s->r.height = geo->src.full_height; break; - case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_COMPOSE_PADDED: s->r.left = geo->dst.x_offset; s->r.top = geo->dst.y_offset; @@ -449,11 +449,11 @@ static int mxr_s_selection(struct file *file, void *fh, res.height = geo->dst.full_height; break; - case V4L2_SEL_TGT_CROP_ACTIVE: + case V4L2_SEL_TGT_CROP: target = &geo->src; stage = MXR_GEOMETRY_CROP; break; - case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_COMPOSE_PADDED: target = &geo->dst; stage = MXR_GEOMETRY_COMPOSE; diff --git a/drivers/media/video/s5p-tv/sii9234_drv.c b/drivers/media/video/s5p-tv/sii9234_drv.c index 0f31eccd7b80..6d348f90237a 100644 --- a/drivers/media/video/s5p-tv/sii9234_drv.c +++ b/drivers/media/video/s5p-tv/sii9234_drv.c @@ -419,14 +419,4 @@ static struct i2c_driver sii9234_driver = { .id_table = sii9234_id, }; -static int __init sii9234_init(void) -{ - return i2c_add_driver(&sii9234_driver); -} -module_init(sii9234_init); - -static void __exit sii9234_exit(void) -{ - i2c_del_driver(&sii9234_driver); -} -module_exit(sii9234_exit); +module_i2c_driver(sii9234_driver); diff --git a/drivers/media/video/saa7121.h b/drivers/media/video/saa7121.h deleted file mode 100644 index 66967ae37494..000000000000 --- a/drivers/media/video/saa7121.h +++ /dev/null @@ -1,132 +0,0 @@ -/* saa7121.h - saa7121 initializations - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ -#ifndef __SAA7121_H__ -#define __SAA7121_H__ - -#define NTSC_BURST_START 0x19 /* 28 */ -#define NTSC_BURST_END 0x1d /* 29 */ -#define NTSC_CHROMA_PHASE 0x67 /* 5a */ -#define NTSC_GAINU 0x76 /* 5b */ -#define NTSC_GAINV 0xa5 /* 5c */ -#define NTSC_BLACK_LEVEL 0x2a /* 5d */ -#define NTSC_BLANKING_LEVEL 0x2e /* 5e */ -#define NTSC_VBI_BLANKING 0x2e /* 5f */ -#define NTSC_DAC_CONTROL 0x11 /* 61 */ -#define NTSC_BURST_AMP 0x3f /* 62 */ -#define NTSC_SUBC3 0x1f /* 63 */ -#define NTSC_SUBC2 0x7c /* 64 */ -#define NTSC_SUBC1 0xf0 /* 65 */ -#define NTSC_SUBC0 0x21 /* 66 */ -#define NTSC_HTRIG 0x72 /* 6c */ -#define NTSC_VTRIG 0x00 /* 6c */ -#define NTSC_MULTI 0x30 /* 6e */ -#define NTSC_CCTTX 0x11 /* 6f */ -#define NTSC_FIRST_ACTIVE 0x12 /* 7a */ -#define NTSC_LAST_ACTIVE 0x02 /* 7b */ -#define NTSC_MSB_VERTICAL 0x40 /* 7c */ - -#define PAL_BURST_START 0x21 /* 28 */ -#define PAL_BURST_END 0x1d /* 29 */ -#define PAL_CHROMA_PHASE 0x3f /* 5a */ -#define PAL_GAINU 0x7d /* 5b */ -#define PAL_GAINV 0xaf /* 5c */ -#define PAL_BLACK_LEVEL 0x23 /* 5d */ -#define PAL_BLANKING_LEVEL 0x35 /* 5e */ -#define PAL_VBI_BLANKING 0x35 /* 5f */ -#define PAL_DAC_CONTROL 0x02 /* 61 */ -#define PAL_BURST_AMP 0x2f /* 62 */ -#define PAL_SUBC3 0xcb /* 63 */ -#define PAL_SUBC2 0x8a /* 64 */ -#define PAL_SUBC1 0x09 /* 65 */ -#define PAL_SUBC0 0x2a /* 66 */ -#define PAL_HTRIG 0x86 /* 6c */ -#define PAL_VTRIG 0x04 /* 6d */ -#define PAL_MULTI 0x20 /* 6e */ -#define PAL_CCTTX 0x15 /* 6f */ -#define PAL_FIRST_ACTIVE 0x16 /* 7a */ -#define PAL_LAST_ACTIVE 0x36 /* 7b */ -#define PAL_MSB_VERTICAL 0x40 /* 7c */ - -/* Initialization Sequence */ - -static __u8 init7121ntsc[] = { - 0x26, 0x0, 0x27, 0x0, - 0x28, NTSC_BURST_START, 0x29, NTSC_BURST_END, - 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, - 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x31, 0x0, - 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, - 0x36, 0x0, 0x37, 0x0, 0x38, 0x0, 0x39, 0x0, - 0x3a, 0x03, 0x3b, 0x0, 0x3c, 0x0, 0x3d, 0x0, - 0x3e, 0x0, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, - 0x42, 0x0, 0x43, 0x0, 0x44, 0x0, 0x45, 0x0, - 0x46, 0x0, 0x47, 0x0, 0x48, 0x0, 0x49, 0x0, - 0x4a, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x4d, 0x0, - 0x4e, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, - 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x55, 0x0, - 0x56, 0x0, 0x57, 0x0, 0x58, 0x0, 0x59, 0x0, - 0x5a, NTSC_CHROMA_PHASE, 0x5b, NTSC_GAINU, - 0x5c, NTSC_GAINV, 0x5d, NTSC_BLACK_LEVEL, - 0x5e, NTSC_BLANKING_LEVEL, 0x5f, NTSC_VBI_BLANKING, - 0x60, 0x0, 0x61, NTSC_DAC_CONTROL, - 0x62, NTSC_BURST_AMP, 0x63, NTSC_SUBC3, - 0x64, NTSC_SUBC2, 0x65, NTSC_SUBC1, - 0x66, NTSC_SUBC0, 0x67, 0x80, 0x68, 0x80, - 0x69, 0x80, 0x6a, 0x80, 0x6b, 0x29, - 0x6c, NTSC_HTRIG, 0x6d, NTSC_VTRIG, - 0x6e, NTSC_MULTI, 0x6f, NTSC_CCTTX, - 0x70, 0xc9, 0x71, 0x68, 0x72, 0x60, 0x73, 0x0, - 0x74, 0x0, 0x75, 0x0, 0x76, 0x0, 0x77, 0x0, - 0x78, 0x0, 0x79, 0x0, 0x7a, NTSC_FIRST_ACTIVE, - 0x7b, NTSC_LAST_ACTIVE, 0x7c, NTSC_MSB_VERTICAL, - 0x7d, 0x0, 0x7e, 0x0, 0x7f, 0x0 -}; -#define INIT7121LEN (sizeof(init7121ntsc)/2) - -static __u8 init7121pal[] = { - 0x26, 0x0, 0x27, 0x0, - 0x28, PAL_BURST_START, 0x29, PAL_BURST_END, - 0x2a, 0x0, 0x2b, 0x0, 0x2c, 0x0, 0x2d, 0x0, - 0x2e, 0x0, 0x2f, 0x0, 0x30, 0x0, 0x31, 0x0, - 0x32, 0x0, 0x33, 0x0, 0x34, 0x0, 0x35, 0x0, - 0x36, 0x0, 0x37, 0x0, 0x38, 0x0, 0x39, 0x0, - 0x3a, 0x03, 0x3b, 0x0, 0x3c, 0x0, 0x3d, 0x0, - 0x3e, 0x0, 0x3f, 0x0, 0x40, 0x0, 0x41, 0x0, - 0x42, 0x0, 0x43, 0x0, 0x44, 0x0, 0x45, 0x0, - 0x46, 0x0, 0x47, 0x0, 0x48, 0x0, 0x49, 0x0, - 0x4a, 0x0, 0x4b, 0x0, 0x4c, 0x0, 0x4d, 0x0, - 0x4e, 0x0, 0x4f, 0x0, 0x50, 0x0, 0x51, 0x0, - 0x52, 0x0, 0x53, 0x0, 0x54, 0x0, 0x55, 0x0, - 0x56, 0x0, 0x57, 0x0, 0x58, 0x0, 0x59, 0x0, - 0x5a, PAL_CHROMA_PHASE, 0x5b, PAL_GAINU, - 0x5c, PAL_GAINV, 0x5d, PAL_BLACK_LEVEL, - 0x5e, PAL_BLANKING_LEVEL, 0x5f, PAL_VBI_BLANKING, - 0x60, 0x0, 0x61, PAL_DAC_CONTROL, - 0x62, PAL_BURST_AMP, 0x63, PAL_SUBC3, - 0x64, PAL_SUBC2, 0x65, PAL_SUBC1, - 0x66, PAL_SUBC0, 0x67, 0x80, 0x68, 0x80, - 0x69, 0x80, 0x6a, 0x80, 0x6b, 0x29, - 0x6c, PAL_HTRIG, 0x6d, PAL_VTRIG, - 0x6e, PAL_MULTI, 0x6f, PAL_CCTTX, - 0x70, 0xc9, 0x71, 0x68, 0x72, 0x60, 0x73, 0x0, - 0x74, 0x0, 0x75, 0x0, 0x76, 0x0, 0x77, 0x0, - 0x78, 0x0, 0x79, 0x0, 0x7a, PAL_FIRST_ACTIVE, - 0x7b, PAL_LAST_ACTIVE, 0x7c, PAL_MSB_VERTICAL, - 0x7d, 0x0, 0x7e, 0x0, 0x7f, 0x0 -}; -#endif diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 5dfd826d734e..cc7f3d6ee966 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1282,7 +1282,7 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: if (configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_PHILIPS_EUROPA: case SAA7134_BOARD_VIDEOMATE_DVBT_300: @@ -1322,7 +1322,7 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_KWORLD_DVBT_210: if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config, &tda827x_cfg_2) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_HAUPPAUGE_HVR1120: fe0->dvb.frontend = dvb_attach(tda10048_attach, @@ -1340,17 +1340,17 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_PHILIPS_TIGER: if (configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_PINNACLE_PCTV_310i: if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, &tda827x_cfg_1) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, &tda827x_cfg_1) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_HAUPPAUGE_HVR1150: fe0->dvb.frontend = dvb_attach(lgdt3305_attach, @@ -1368,30 +1368,30 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_P7131_DUAL: if (configure_tda827x_fe(dev, &asus_p7131_dual_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_FLYDVBT_LR301: if (configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_FLYDVB_TRIO: if (!use_frontend) { /* terrestrial */ if (configure_tda827x_fe(dev, &lifeview_trio_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; } else { /* satellite */ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); if (fe0->dvb.frontend) { if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63, &dev->i2c_adap, 0) == NULL) { wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0) == NULL) { wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } } } @@ -1407,7 +1407,7 @@ static int dvb_init(struct saa7134_dev *dev) &ads_duo_cfg) == NULL) { wprintk("no tda827x tuner found at addr: %02x\n", ads_tech_duo_config.tuner_address); - goto dettach_frontend; + goto detach_frontend; } } else wprintk("failed to attach tda10046\n"); @@ -1415,13 +1415,13 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_TEVION_DVBT_220RF: if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_MEDION_MD8800_QUADRO: if (!use_frontend) { /* terrestrial */ if (configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; } else { /* satellite */ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); @@ -1435,7 +1435,7 @@ static int dvb_init(struct saa7134_dev *dev) 0x60, &dev->i2c_adap, 0) == NULL) { wprintk("%s: Medion Quadro, no tda826x " "found !\n", __func__); - goto dettach_frontend; + goto detach_frontend; } if (dev_id != 0x08) { /* we need to open the i2c gate (we know it exists) */ @@ -1444,7 +1444,7 @@ static int dvb_init(struct saa7134_dev *dev) &dev->i2c_adap, 0x08, 0, 0) == NULL) { wprintk("%s: Medion Quadro, no ISL6405 " "found !\n", __func__); - goto dettach_frontend; + goto detach_frontend; } if (dev_id == 0x07) { /* fire up the 2nd section of the LNB supply since @@ -1503,12 +1503,12 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { wprintk("%s: No tda826x found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0) == NULL) { wprintk("%s: No ISL6421 found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } } break; @@ -1537,37 +1537,37 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_CINERGY_HT_PCMCIA: if (configure_tda827x_fe(dev, &cinergy_ht_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_CINERGY_HT_PCI: if (configure_tda827x_fe(dev, &cinergy_ht_pci_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_PHILIPS_TIGER_S: if (configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_ASUS_P7131_4871: if (configure_tda827x_fe(dev, &asus_p7131_4871_config, &tda827x_cfg_2) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, &tda827x_cfg_2) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_AVERMEDIA_SUPER_007: if (configure_tda827x_fe(dev, &avermedia_super_007_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, &tda827x_cfg_2_sw42) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_PHILIPS_SNAKE: fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, @@ -1576,24 +1576,24 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { wprintk("%s: No tda826x found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { wprintk("%s: No lnbp21 found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } } break; case SAA7134_BOARD_CREATIX_CTX953: if (configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_MSI_TVANYWHERE_AD11: if (configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: dprintk("AverMedia E506R dvb setup\n"); @@ -1614,7 +1614,7 @@ static int dvb_init(struct saa7134_dev *dev) &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) { wprintk("%s: MD7134 DVB-S, no SD1878 " "found !\n", __func__); - goto dettach_frontend; + goto detach_frontend; } /* we need to open the i2c gate (we know it exists) */ fe = fe0->dvb.frontend; @@ -1623,7 +1623,7 @@ static int dvb_init(struct saa7134_dev *dev) &dev->i2c_adap, 0x08, 0, 0) == NULL) { wprintk("%s: MD7134 DVB-S, no ISL6405 " "found !\n", __func__); - goto dettach_frontend; + goto detach_frontend; } fe->ops.i2c_gate_ctrl(fe, 0); dev->original_set_voltage = fe->ops.set_voltage; @@ -1645,7 +1645,7 @@ static int dvb_init(struct saa7134_dev *dev) if (!use_frontend) { /* terrestrial */ if (configure_tda827x_fe(dev, &asus_tiger_3in1_config, &tda827x_cfg_2) < 0) - goto dettach_frontend; + goto detach_frontend; } else { /* satellite */ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); @@ -1655,13 +1655,13 @@ static int dvb_init(struct saa7134_dev *dev) &dev->i2c_adap, 0) == NULL) { wprintk("%s: Asus Tiger 3in1, no " "tda826x found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { wprintk("%s: Asus Tiger 3in1, no lnbp21" " found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } } } @@ -1670,7 +1670,7 @@ static int dvb_init(struct saa7134_dev *dev) if (!use_frontend) { /* terrestrial */ if (configure_tda827x_fe(dev, &asus_ps3_100_config, &tda827x_cfg_2) < 0) - goto dettach_frontend; + goto detach_frontend; } else { /* satellite */ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); @@ -1680,13 +1680,13 @@ static int dvb_init(struct saa7134_dev *dev) &dev->i2c_adap, 0) == NULL) { wprintk("%s: Asus My Cinema PS3-100, no " "tda826x found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { wprintk("%s: Asus My Cinema PS3-100, no lnbp21" " found!\n", __func__); - goto dettach_frontend; + goto detach_frontend; } } } @@ -1694,7 +1694,7 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_TIGER: if (configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0) < 0) - goto dettach_frontend; + goto detach_frontend; break; case SAA7134_BOARD_BEHOLD_H6: fe0->dvb.frontend = dvb_attach(zl10353_attach, @@ -1830,19 +1830,19 @@ static int dvb_init(struct saa7134_dev *dev) }; if (!fe0->dvb.frontend) - goto dettach_frontend; + goto detach_frontend; fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); if (!fe) { printk(KERN_ERR "%s/2: xc3028 attach failed\n", dev->name); - goto dettach_frontend; + goto detach_frontend; } } if (NULL == fe0->dvb.frontend) { printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); - goto dettach_frontend; + goto detach_frontend; } /* define general-purpose callback pointer */ fe0->dvb.frontend->callback = saa7134_tuner_callback; @@ -1864,7 +1864,7 @@ static int dvb_init(struct saa7134_dev *dev) } return ret; -dettach_frontend: +detach_frontend: videobuf_dvb_dealloc_frontends(&dev->frontends); return -EINVAL; } diff --git a/drivers/media/video/saa7146.h b/drivers/media/video/saa7146.h deleted file mode 100644 index 9fadb331a40b..000000000000 --- a/drivers/media/video/saa7146.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - saa7146.h - definitions philips saa7146 based cards - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __SAA7146__ -#define __SAA7146__ - -#define SAA7146_VERSION_CODE 0x000101 - -#include <linux/types.h> -#include <linux/wait.h> - -#ifndef O_NONCAP -#define O_NONCAP O_TRUNC -#endif - -#define MAX_GBUFFERS 2 -#define FBUF_SIZE 0x190000 - -#ifdef __KERNEL__ - -struct saa7146_window -{ - int x, y; - ushort width, height; - ushort bpp, bpl; - ushort swidth, sheight; - short cropx, cropy; - ushort cropwidth, cropheight; - unsigned long vidadr; - int color_fmt; - ushort depth; -}; - -/* Per-open data for handling multiple opens on one device */ -struct device_open -{ - int isopen; - int noncapturing; - struct saa7146 *dev; -}; -#define MAX_OPENS 3 - -struct saa7146 -{ - struct video_device video_dev; - struct video_picture picture; - struct video_audio audio_dev; - struct video_info vidinfo; - int user; - int cap; - int capuser; - int irqstate; /* irq routine is state driven */ - int writemode; - int playmode; - unsigned int nr; - unsigned long irq; /* IRQ used by SAA7146 card */ - unsigned short id; - unsigned char revision; - unsigned char boardcfg[64]; /* 64 bytes of config from eeprom */ - unsigned long saa7146_adr; /* bus address of IO mem from PCI BIOS */ - struct saa7146_window win; - unsigned char __iomem *saa7146_mem; /* pointer to mapped IO memory */ - struct device_open open_data[MAX_OPENS]; -#define MAX_MARKS 16 - /* for a/v sync */ - int endmark[MAX_MARKS], endmarkhead, endmarktail; - u32 *dmaRPS1, *pageRPS1, *dmaRPS2, *pageRPS2, *dmavid1, *dmavid2, - *dmavid3, *dmaa1in, *dmaa1out, *dmaa2in, *dmaa2out, - *pagedebi, *pagevid1, *pagevid2, *pagevid3, *pagea1in, - *pagea1out, *pagea2in, *pagea2out; - wait_queue_head_t i2cq, debiq, audq, vidq; - u8 *vidbuf, *audbuf, *osdbuf, *dmadebi; - int audhead, vidhead, osdhead, audtail, vidtail, osdtail; - spinlock_t lock; /* the device lock */ -}; -#endif - -#ifdef _ALPHA_SAA7146 -#define saawrite(dat,adr) writel((dat), saa->saa7146_adr+(adr)) -#define saaread(adr) readl(saa->saa7146_adr+(adr)) -#else -#define saawrite(dat,adr) writel((dat), saa->saa7146_mem+(adr)) -#define saaread(adr) readl(saa->saa7146_mem+(adr)) -#endif - -#define saaand(dat,adr) saawrite((dat) & saaread(adr), adr) -#define saaor(dat,adr) saawrite((dat) | saaread(adr), adr) -#define saaaor(dat,mask,adr) saawrite((dat) | ((mask) & saaread(adr)), adr) - -/* bitmask of attached hardware found */ -#define SAA7146_UNKNOWN 0x00000000 -#define SAA7146_SAA7111 0x00000001 -#define SAA7146_SAA7121 0x00000002 -#define SAA7146_IBMMPEG 0x00000004 - -#endif diff --git a/drivers/media/video/saa7146reg.h b/drivers/media/video/saa7146reg.h deleted file mode 100644 index 80ec2c146b4c..000000000000 --- a/drivers/media/video/saa7146reg.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - saa7146.h - definitions philips saa7146 based cards - Copyright (C) 1999 Nathan Laredo (laredo@gnu.org) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef __SAA7146_REG__ -#define __SAA7146_REG__ -#define SAA7146_BASE_ODD1 0x00 -#define SAA7146_BASE_EVEN1 0x04 -#define SAA7146_PROT_ADDR1 0x08 -#define SAA7146_PITCH1 0x0c -#define SAA7146_PAGE1 0x10 -#define SAA7146_NUM_LINE_BYTE1 0x14 -#define SAA7146_BASE_ODD2 0x18 -#define SAA7146_BASE_EVEN2 0x1c -#define SAA7146_PROT_ADDR2 0x20 -#define SAA7146_PITCH2 0x24 -#define SAA7146_PAGE2 0x28 -#define SAA7146_NUM_LINE_BYTE2 0x2c -#define SAA7146_BASE_ODD3 0x30 -#define SAA7146_BASE_EVEN3 0x34 -#define SAA7146_PROT_ADDR3 0x38 -#define SAA7146_PITCH3 0x3c -#define SAA7146_PAGE3 0x40 -#define SAA7146_NUM_LINE_BYTE3 0x44 -#define SAA7146_PCI_BT_V1 0x48 -#define SAA7146_PCI_BT_V2 0x49 -#define SAA7146_PCI_BT_V3 0x4a -#define SAA7146_PCI_BT_DEBI 0x4b -#define SAA7146_PCI_BT_A 0x4c -#define SAA7146_DD1_INIT 0x50 -#define SAA7146_DD1_STREAM_B 0x54 -#define SAA7146_DD1_STREAM_A 0x56 -#define SAA7146_BRS_CTRL 0x58 -#define SAA7146_HPS_CTRL 0x5c -#define SAA7146_HPS_V_SCALE 0x60 -#define SAA7146_HPS_V_GAIN 0x64 -#define SAA7146_HPS_H_PRESCALE 0x68 -#define SAA7146_HPS_H_SCALE 0x6c -#define SAA7146_BCS_CTRL 0x70 -#define SAA7146_CHROMA_KEY_RANGE 0x74 -#define SAA7146_CLIP_FORMAT_CTRL 0x78 -#define SAA7146_DEBI_CONFIG 0x7c -#define SAA7146_DEBI_COMMAND 0x80 -#define SAA7146_DEBI_PAGE 0x84 -#define SAA7146_DEBI_AD 0x88 -#define SAA7146_I2C_TRANSFER 0x8c -#define SAA7146_I2C_STATUS 0x90 -#define SAA7146_BASE_A1_IN 0x94 -#define SAA7146_PROT_A1_IN 0x98 -#define SAA7146_PAGE_A1_IN 0x9C -#define SAA7146_BASE_A1_OUT 0xa0 -#define SAA7146_PROT_A1_OUT 0xa4 -#define SAA7146_PAGE_A1_OUT 0xa8 -#define SAA7146_BASE_A2_IN 0xac -#define SAA7146_PROT_A2_IN 0xb0 -#define SAA7146_PAGE_A2_IN 0xb4 -#define SAA7146_BASE_A2_OUT 0xb8 -#define SAA7146_PROT_A2_OUT 0xbc -#define SAA7146_PAGE_A2_OUT 0xc0 -#define SAA7146_RPS_PAGE0 0xc4 -#define SAA7146_RPS_PAGE1 0xc8 -#define SAA7146_RPS_THRESH0 0xcc -#define SAA7146_RPS_THRESH1 0xd0 -#define SAA7146_RPS_TOV0 0xd4 -#define SAA7146_RPS_TOV1 0xd8 -#define SAA7146_IER 0xdc -#define SAA7146_GPIO_CTRL 0xe0 -#define SAA7146_EC1SSR 0xe4 -#define SAA7146_EC2SSR 0xe8 -#define SAA7146_ECT1R 0xec -#define SAA7146_ECT2R 0xf0 -#define SAA7146_ACON1 0xf4 -#define SAA7146_ACON2 0xf8 -#define SAA7146_MC1 0xfc -#define SAA7146_MC2 0x100 -#define SAA7146_RPS_ADDR0 0x104 -#define SAA7146_RPS_ADDR1 0x108 -#define SAA7146_ISR 0x10c -#define SAA7146_PSR 0x110 -#define SAA7146_SSR 0x114 -#define SAA7146_EC1R 0x118 -#define SAA7146_EC2R 0x11c -#define SAA7146_VDP1 0x120 -#define SAA7146_VDP2 0x124 -#define SAA7146_VDP3 0x128 -#define SAA7146_ADP1 0x12c -#define SAA7146_ADP2 0x130 -#define SAA7146_ADP3 0x134 -#define SAA7146_ADP4 0x138 -#define SAA7146_DDP 0x13c -#define SAA7146_LEVEL_REP 0x140 -#define SAA7146_FB_BUFFER1 0x144 -#define SAA7146_FB_BUFFER2 0x148 -#define SAA7146_A_TIME_SLOT1 0x180 -#define SAA7146_A_TIME_SLOT2 0x1C0 - -/* bitfield defines */ -#define MASK_31 0x80000000 -#define MASK_30 0x40000000 -#define MASK_29 0x20000000 -#define MASK_28 0x10000000 -#define MASK_27 0x08000000 -#define MASK_26 0x04000000 -#define MASK_25 0x02000000 -#define MASK_24 0x01000000 -#define MASK_23 0x00800000 -#define MASK_22 0x00400000 -#define MASK_21 0x00200000 -#define MASK_20 0x00100000 -#define MASK_19 0x00080000 -#define MASK_18 0x00040000 -#define MASK_17 0x00020000 -#define MASK_16 0x00010000 -#define MASK_15 0x00008000 -#define MASK_14 0x00004000 -#define MASK_13 0x00002000 -#define MASK_12 0x00001000 -#define MASK_11 0x00000800 -#define MASK_10 0x00000400 -#define MASK_09 0x00000200 -#define MASK_08 0x00000100 -#define MASK_07 0x00000080 -#define MASK_06 0x00000040 -#define MASK_05 0x00000020 -#define MASK_04 0x00000010 -#define MASK_03 0x00000008 -#define MASK_02 0x00000004 -#define MASK_01 0x00000002 -#define MASK_00 0x00000001 -#define MASK_B0 0x000000ff -#define MASK_B1 0x0000ff00 -#define MASK_B2 0x00ff0000 -#define MASK_B3 0xff000000 -#define MASK_W0 0x0000ffff -#define MASK_W1 0xffff0000 -#define MASK_PA 0xfffffffc -#define MASK_PR 0xfffffffe -#define MASK_ER 0xffffffff -#define MASK_NONE 0x00000000 - -#define SAA7146_PAGE_MAP_EN MASK_11 -/* main control register 1 */ -#define SAA7146_MC1_MRST_N MASK_15 -#define SAA7146_MC1_ERPS1 MASK_13 -#define SAA7146_MC1_ERPS0 MASK_12 -#define SAA7146_MC1_EDP MASK_11 -#define SAA7146_MC1_EVP MASK_10 -#define SAA7146_MC1_EAP MASK_09 -#define SAA7146_MC1_EI2C MASK_08 -#define SAA7146_MC1_TR_E_DEBI MASK_07 -#define SAA7146_MC1_TR_E_1 MASK_06 -#define SAA7146_MC1_TR_E_2 MASK_05 -#define SAA7146_MC1_TR_E_3 MASK_04 -#define SAA7146_MC1_TR_E_A2_OUT MASK_03 -#define SAA7146_MC1_TR_E_A2_IN MASK_02 -#define SAA7146_MC1_TR_E_A1_OUT MASK_01 -#define SAA7146_MC1_TR_E_A1_IN MASK_00 -/* main control register 2 */ -#define SAA7146_MC2_RPS_SIG4 MASK_15 -#define SAA7146_MC2_RPS_SIG3 MASK_14 -#define SAA7146_MC2_RPS_SIG2 MASK_13 -#define SAA7146_MC2_RPS_SIG1 MASK_12 -#define SAA7146_MC2_RPS_SIG0 MASK_11 -#define SAA7146_MC2_UPLD_D1_B MASK_10 -#define SAA7146_MC2_UPLD_D1_A MASK_09 -#define SAA7146_MC2_UPLD_BRS MASK_08 -#define SAA7146_MC2_UPLD_HPS_H MASK_06 -#define SAA7146_MC2_UPLD_HPS_V MASK_05 -#define SAA7146_MC2_UPLD_DMA3 MASK_04 -#define SAA7146_MC2_UPLD_DMA2 MASK_03 -#define SAA7146_MC2_UPLD_DMA1 MASK_02 -#define SAA7146_MC2_UPLD_DEBI MASK_01 -#define SAA7146_MC2_UPLD_I2C MASK_00 -/* Primary Status Register and Interrupt Enable/Status Registers */ -#define SAA7146_PSR_PPEF MASK_31 -#define SAA7146_PSR_PABO MASK_30 -#define SAA7146_PSR_PPED MASK_29 -#define SAA7146_PSR_RPS_I1 MASK_28 -#define SAA7146_PSR_RPS_I0 MASK_27 -#define SAA7146_PSR_RPS_LATE1 MASK_26 -#define SAA7146_PSR_RPS_LATE0 MASK_25 -#define SAA7146_PSR_RPS_E1 MASK_24 -#define SAA7146_PSR_RPS_E0 MASK_23 -#define SAA7146_PSR_RPS_TO1 MASK_22 -#define SAA7146_PSR_RPS_TO0 MASK_21 -#define SAA7146_PSR_UPLD MASK_20 -#define SAA7146_PSR_DEBI_S MASK_19 -#define SAA7146_PSR_DEBI_E MASK_18 -#define SAA7146_PSR_I2C_S MASK_17 -#define SAA7146_PSR_I2C_E MASK_16 -#define SAA7146_PSR_A2_IN MASK_15 -#define SAA7146_PSR_A2_OUT MASK_14 -#define SAA7146_PSR_A1_IN MASK_13 -#define SAA7146_PSR_A1_OUT MASK_12 -#define SAA7146_PSR_AFOU MASK_11 -#define SAA7146_PSR_V_PE MASK_10 -#define SAA7146_PSR_VFOU MASK_09 -#define SAA7146_PSR_FIDA MASK_08 -#define SAA7146_PSR_FIDB MASK_07 -#define SAA7146_PSR_PIN3 MASK_06 -#define SAA7146_PSR_PIN2 MASK_05 -#define SAA7146_PSR_PIN1 MASK_04 -#define SAA7146_PSR_PIN0 MASK_03 -#define SAA7146_PSR_ECS MASK_02 -#define SAA7146_PSR_EC3S MASK_01 -#define SAA7146_PSR_EC0S MASK_00 -/* Secondary Status Register */ -#define SAA7146_SSR_PRQ MASK_31 -#define SAA7146_SSR_PMA MASK_30 -#define SAA7146_SSR_RPS_RE1 MASK_29 -#define SAA7146_SSR_RPS_PE1 MASK_28 -#define SAA7146_SSR_RPS_A1 MASK_27 -#define SAA7146_SSR_RPS_RE0 MASK_26 -#define SAA7146_SSR_RPS_PE0 MASK_25 -#define SAA7146_SSR_RPS_A0 MASK_24 -#define SAA7146_SSR_DEBI_TO MASK_23 -#define SAA7146_SSR_DEBI_EF MASK_22 -#define SAA7146_SSR_I2C_EA MASK_21 -#define SAA7146_SSR_I2C_EW MASK_20 -#define SAA7146_SSR_I2C_ER MASK_19 -#define SAA7146_SSR_I2C_EL MASK_18 -#define SAA7146_SSR_I2C_EF MASK_17 -#define SAA7146_SSR_V3P MASK_16 -#define SAA7146_SSR_V2P MASK_15 -#define SAA7146_SSR_V1P MASK_14 -#define SAA7146_SSR_VF3 MASK_13 -#define SAA7146_SSR_VF2 MASK_12 -#define SAA7146_SSR_VF1 MASK_11 -#define SAA7146_SSR_AF2_IN MASK_10 -#define SAA7146_SSR_AF2_OUT MASK_09 -#define SAA7146_SSR_AF1_IN MASK_08 -#define SAA7146_SSR_AF1_OUT MASK_07 -#define SAA7146_SSR_VGT MASK_05 -#define SAA7146_SSR_LNQG MASK_04 -#define SAA7146_SSR_EC5S MASK_03 -#define SAA7146_SSR_EC4S MASK_02 -#define SAA7146_SSR_EC2S MASK_01 -#define SAA7146_SSR_EC1S MASK_00 -/* I2C status register */ -#define SAA7146_I2C_ABORT MASK_07 -#define SAA7146_I2C_SPERR MASK_06 -#define SAA7146_I2C_APERR MASK_05 -#define SAA7146_I2C_DTERR MASK_04 -#define SAA7146_I2C_DRERR MASK_03 -#define SAA7146_I2C_AL MASK_02 -#define SAA7146_I2C_ERR MASK_01 -#define SAA7146_I2C_BUSY MASK_00 -/* output formats */ -#define SAA7146_YUV422 0 -#define SAA7146_RGB16 0 -#define SAA7146_YUV444 1 -#define SAA7146_RGB24 1 -#define SAA7146_ARGB32 2 -#define SAA7146_YUV411 3 -#define SAA7146_ARGB15 3 -#define SAA7146_YUV2 4 -#define SAA7146_RGAB15 4 -#define SAA7146_Y8 6 -#define SAA7146_YUV8 7 -#define SAA7146_RGB8 7 -#define SAA7146_YUV444p 8 -#define SAA7146_YUV422p 9 -#define SAA7146_YUV420p 10 -#define SAA7146_YUV1620 11 -#define SAA7146_Y1 13 -#define SAA7146_Y2 14 -#define SAA7146_YUV1 15 -#endif diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c index 8a98ab68239e..c8799fdaae67 100644 --- a/drivers/media/video/saa7164/saa7164-api.c +++ b/drivers/media/video/saa7164/saa7164-api.c @@ -1367,7 +1367,6 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, struct saa7164_dev *dev = bus->dev; u16 len = 0; int unitid; - u32 regval; u8 buf[256]; int ret; @@ -1376,19 +1375,6 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, if (reglen > 4) return -EIO; - if (reglen == 1) - regval = *(reg); - else - if (reglen == 2) - regval = ((*(reg) << 8) || *(reg+1)); - else - if (reglen == 3) - regval = ((*(reg) << 16) | (*(reg+1) << 8) | *(reg+2)); - else - if (reglen == 4) - regval = ((*(reg) << 24) | (*(reg+1) << 16) | - (*(reg+2) << 8) | *(reg+3)); - /* Prepare the send buffer */ /* Bytes 00-03 source register length * 04-07 source bytes to read diff --git a/drivers/media/video/saa7164/saa7164-i2c.c b/drivers/media/video/saa7164/saa7164-i2c.c index 26148f76cba2..4f7e3b42263f 100644 --- a/drivers/media/video/saa7164/saa7164-i2c.c +++ b/drivers/media/video/saa7164/saa7164-i2c.c @@ -69,15 +69,6 @@ err: return retval; } -void saa7164_call_i2c_clients(struct saa7164_i2c *bus, unsigned int cmd, - void *arg) -{ - if (bus->i2c_rc != 0) - return; - - i2c_clients_command(&bus->i2c_adap, cmd, arg); -} - static u32 saa7164_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C; @@ -106,21 +97,14 @@ int saa7164_i2c_register(struct saa7164_i2c *bus) dprintk(DBGLVL_I2C, "%s(bus = %d)\n", __func__, bus->nr); - memcpy(&bus->i2c_adap, &saa7164_i2c_adap_template, - sizeof(bus->i2c_adap)); - - memcpy(&bus->i2c_algo, &saa7164_i2c_algo_template, - sizeof(bus->i2c_algo)); - - memcpy(&bus->i2c_client, &saa7164_i2c_client_template, - sizeof(bus->i2c_client)); + bus->i2c_adap = saa7164_i2c_adap_template; + bus->i2c_client = saa7164_i2c_client_template; bus->i2c_adap.dev.parent = &dev->pci->dev; strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); - bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; i2c_set_adapdata(&bus->i2c_adap, bus); i2c_add_adapter(&bus->i2c_adap); diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h index 8d120e3baf70..35219b9b0fbc 100644 --- a/drivers/media/video/saa7164/saa7164.h +++ b/drivers/media/video/saa7164/saa7164.h @@ -46,7 +46,6 @@ #include <linux/pci.h> #include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> #include <linux/kdev_t.h> #include <linux/mutex.h> #include <linux/crc32.h> @@ -251,7 +250,6 @@ struct saa7164_i2c { /* I2C I/O */ struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_algo; struct i2c_client i2c_client; u32 i2c_rc; }; diff --git a/drivers/media/video/smiapp/Kconfig b/drivers/media/video/smiapp/Kconfig index fb99ff18be07..3149cda1d0db 100644 --- a/drivers/media/video/smiapp/Kconfig +++ b/drivers/media/video/smiapp/Kconfig @@ -1,6 +1,7 @@ config VIDEO_SMIAPP tristate "SMIA++/SMIA sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAVE_CLK + depends on MEDIA_CAMERA_SUPPORT select VIDEO_SMIAPP_PLL ---help--- This is a generic driver for SMIA++/SMIA camera modules. diff --git a/drivers/media/video/smiapp/smiapp-core.c b/drivers/media/video/smiapp/smiapp-core.c index e8c93c89265a..bfd47c106134 100644 --- a/drivers/media/video/smiapp/smiapp-core.c +++ b/drivers/media/video/smiapp/smiapp-core.c @@ -31,16 +31,16 @@ #include <linux/device.h> #include <linux/gpio.h> #include <linux/module.h> -#include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/regulator/consumer.h> #include <linux/v4l2-mediabus.h> #include <media/v4l2-device.h> #include "smiapp.h" -#define SMIAPP_ALIGN_DIM(dim, flags) \ - ((flags) & V4L2_SUBDEV_SEL_FLAG_SIZE_GE \ - ? ALIGN((dim), 2) \ +#define SMIAPP_ALIGN_DIM(dim, flags) \ + ((flags) & V4L2_SEL_FLAG_GE \ + ? ALIGN((dim), 2) \ : (dim) & ~1) /* @@ -1630,7 +1630,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev, smiapp_get_crop_compose(subdev, fh, crops, &comp, which); switch (target) { - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: + case V4L2_SEL_TGT_CROP: comp->width = crops[SMIAPP_PAD_SINK]->width; comp->height = crops[SMIAPP_PAD_SINK]->height; if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { @@ -1646,7 +1646,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev, } } /* Fall through */ - case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL: + case V4L2_SEL_TGT_COMPOSE: *crops[SMIAPP_PAD_SRC] = *comp; break; default: @@ -1722,7 +1722,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) ssd->sink_fmt = *crops[ssd->sink_pad]; smiapp_propagate(subdev, fh, fmt->which, - V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL); + V4L2_SEL_TGT_CROP); mutex_unlock(&sensor->mutex); @@ -1747,14 +1747,14 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, h &= ~1; ask_h &= ~1; - if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_GE) { + if (flags & V4L2_SEL_FLAG_GE) { if (w < ask_w) val -= SCALING_GOODNESS; if (h < ask_h) val -= SCALING_GOODNESS; } - if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_LE) { + if (flags & V4L2_SEL_FLAG_LE) { if (w > ask_w) val -= SCALING_GOODNESS; if (h > ask_h) @@ -1957,7 +1957,7 @@ static int smiapp_set_compose(struct v4l2_subdev *subdev, *comp = sel->r; smiapp_propagate(subdev, fh, sel->which, - V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL); + V4L2_SEL_TGT_COMPOSE); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) return smiapp_update_mode(sensor); @@ -1973,8 +1973,8 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev, /* We only implement crop in three places. */ switch (sel->target) { - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: - case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_BOUNDS: if (ssd == sensor->pixel_array && sel->pad == SMIAPP_PA_PAD_SRC) return 0; @@ -1987,8 +1987,8 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev, == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) return 0; return -EINVAL; - case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL: - case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: if (sel->pad == ssd->source_pad) return -EINVAL; if (ssd == sensor->binner) @@ -2050,7 +2050,7 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK) smiapp_propagate(subdev, fh, sel->which, - V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL); + V4L2_SEL_TGT_CROP); return 0; } @@ -2084,7 +2084,7 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev, } switch (sel->target) { - case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_BOUNDS: if (ssd == sensor->pixel_array) { sel->r.width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; @@ -2096,11 +2096,11 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev, sel->r = *comp; } break; - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: - case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: sel->r = *crops[sel->pad]; break; - case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL: + case V4L2_SEL_TGT_COMPOSE: sel->r = *comp; break; } @@ -2147,10 +2147,10 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev, sel->r.height); switch (sel->target) { - case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: + case V4L2_SEL_TGT_CROP: ret = smiapp_set_crop(subdev, fh, sel); break; - case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL: + case V4L2_SEL_TGT_COMPOSE: ret = smiapp_set_compose(subdev, fh, sel); break; default: diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h index 22ea211ab54f..2bc153e869be 100644 --- a/drivers/media/video/sn9c102/sn9c102.h +++ b/drivers/media/video/sn9c102/sn9c102.h @@ -182,7 +182,7 @@ do { \ # define V4LDBG(level, name, cmd) \ do { \ if (debug >= (level)) \ - v4l_print_ioctl(name, cmd); \ + v4l_printk_ioctl(name, cmd); \ } while (0) # define KDBG(level, fmt, args...) \ do { \ diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 0421bf9453b4..b03ffecb7438 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -62,7 +62,7 @@ static int soc_camera_power_on(struct soc_camera_device *icd, } if (icl->power) { - ret = icl->power(icd->pdev, 1); + ret = icl->power(icd->control, 1); if (ret < 0) { dev_err(icd->pdev, "Platform failed to power-on the camera.\n"); @@ -78,7 +78,7 @@ static int soc_camera_power_on(struct soc_camera_device *icd, esdpwr: if (icl->power) - icl->power(icd->pdev, 0); + icl->power(icd->control, 0); elinkpwr: regulator_bulk_disable(icl->num_regulators, icl->regulators); @@ -95,7 +95,7 @@ static int soc_camera_power_off(struct soc_camera_device *icd, return ret; if (icl->power) { - ret = icl->power(icd->pdev, 0); + ret = icl->power(icd->control, 0); if (ret < 0) { dev_err(icd->pdev, "Platform failed to power-off the camera.\n"); @@ -1518,6 +1518,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) } static struct platform_driver __refdata soc_camera_pdrv = { + .probe = soc_camera_pdrv_probe, .remove = __devexit_p(soc_camera_pdrv_remove), .driver = { .name = "soc-camera-pdrv", @@ -1527,7 +1528,7 @@ static struct platform_driver __refdata soc_camera_pdrv = { static int __init soc_camera_init(void) { - return platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe); + return platform_driver_register(&soc_camera_pdrv); } static void __exit soc_camera_exit(void) diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c index c096b3f74200..7b1f6ebd0e2c 100644 --- a/drivers/media/video/tlg2300/pd-main.c +++ b/drivers/media/video/tlg2300/pd-main.c @@ -53,7 +53,8 @@ int debug_mode; module_param(debug_mode, int, 0644); MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose"); -static const char *firmware_name = "tlg2300_firmware.bin"; +#define TLG2300_FIRMWARE "tlg2300_firmware.bin" +static const char *firmware_name = TLG2300_FIRMWARE; static struct usb_driver poseidon_driver; static LIST_HEAD(pd_device_list); @@ -532,3 +533,4 @@ MODULE_AUTHOR("Telegent Systems"); MODULE_DESCRIPTION("For tlg2300-based USB device "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.0.2"); +MODULE_FIRMWARE(TLG2300_FIRMWARE); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 1ad5ab6ce5cf..b5a819af2b8c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -228,6 +228,16 @@ static int fe_has_signal(struct dvb_frontend *fe) return strength; } +static int fe_get_afc(struct dvb_frontend *fe) +{ + s32 afc = 0; + + if (fe->ops.tuner_ops.get_afc) + fe->ops.tuner_ops.get_afc(fe, &afc); + + return 0; +} + static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) { struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; @@ -247,6 +257,7 @@ static struct analog_demod_ops tuner_analog_ops = { .set_params = fe_set_params, .standby = fe_standby, .has_signal = fe_has_signal, + .get_afc = fe_get_afc, .set_config = fe_set_config, .tuner_status = tuner_status }; @@ -1178,6 +1189,8 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; if (vt->type == t->mode && analog_ops->get_afc) vt->afc = analog_ops->get_afc(&t->fe); + if (analog_ops->has_signal) + vt->signal = analog_ops->has_signal(&t->fe); if (vt->type != V4L2_TUNER_RADIO) { vt->capability |= V4L2_TUNER_CAP_NORM; vt->rangelow = tv_range[0] * 16; @@ -1197,8 +1210,6 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } - if (analog_ops->has_signal) - vt->signal = analog_ops->has_signal(&t->fe); vt->audmode = t->audmode; } vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index c5b1a7365e4f..321b3153df87 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -59,8 +59,8 @@ struct CHIPSTATE; typedef int (*getvalue)(int); typedef int (*checkit)(struct CHIPSTATE*); typedef int (*initialize)(struct CHIPSTATE*); -typedef int (*getmode)(struct CHIPSTATE*); -typedef void (*setmode)(struct CHIPSTATE*, int mode); +typedef int (*getrxsubchans)(struct CHIPSTATE *); +typedef void (*setaudmode)(struct CHIPSTATE*, int mode); /* i2c command */ typedef struct AUDIOCMD { @@ -96,8 +96,8 @@ struct CHIPDESC { getvalue volfunc,treblefunc,bassfunc; /* get/set mode */ - getmode getmode; - setmode setmode; + getrxsubchans getrxsubchans; + setaudmode setaudmode; /* input switch register + values for v4l inputs */ int inputreg; @@ -118,7 +118,7 @@ struct CHIPSTATE { audiocmd shadow; /* current settings */ - __u16 left,right,treble,bass,muted,mode; + __u16 left, right, treble, bass, muted; int prevmode; int radio; int input; @@ -126,7 +126,6 @@ struct CHIPSTATE { /* thread */ struct task_struct *thread; struct timer_list wt; - int watch_stereo; int audmode; }; @@ -288,7 +287,7 @@ static int chip_thread(void *data) struct CHIPSTATE *chip = data; struct CHIPDESC *desc = chip->desc; struct v4l2_subdev *sd = &chip->sd; - int mode; + int mode, selected; v4l2_dbg(1, debug, sd, "thread started\n"); set_freezable(); @@ -302,12 +301,12 @@ static int chip_thread(void *data) break; v4l2_dbg(1, debug, sd, "thread wakeup\n"); - /* don't do anything for radio or if mode != auto */ - if (chip->radio || chip->mode != 0) + /* don't do anything for radio */ + if (chip->radio) continue; /* have a look what's going on */ - mode = desc->getmode(chip); + mode = desc->getrxsubchans(chip); if (mode == chip->prevmode) continue; @@ -316,16 +315,32 @@ static int chip_thread(void *data) chip->prevmode = mode; - if (mode & V4L2_TUNER_MODE_STEREO) - desc->setmode(chip, V4L2_TUNER_MODE_STEREO); - if (mode & V4L2_TUNER_MODE_LANG1_LANG2) - desc->setmode(chip, V4L2_TUNER_MODE_STEREO); - else if (mode & V4L2_TUNER_MODE_LANG1) - desc->setmode(chip, V4L2_TUNER_MODE_LANG1); - else if (mode & V4L2_TUNER_MODE_LANG2) - desc->setmode(chip, V4L2_TUNER_MODE_LANG2); - else - desc->setmode(chip, V4L2_TUNER_MODE_MONO); + selected = V4L2_TUNER_MODE_MONO; + switch (chip->audmode) { + case V4L2_TUNER_MODE_MONO: + if (mode & V4L2_TUNER_SUB_LANG1) + selected = V4L2_TUNER_MODE_LANG1; + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + if (mode & V4L2_TUNER_SUB_LANG1) + selected = V4L2_TUNER_MODE_LANG1; + else if (mode & V4L2_TUNER_SUB_STEREO) + selected = V4L2_TUNER_MODE_STEREO; + break; + case V4L2_TUNER_MODE_LANG2: + if (mode & V4L2_TUNER_SUB_LANG2) + selected = V4L2_TUNER_MODE_LANG2; + else if (mode & V4L2_TUNER_SUB_STEREO) + selected = V4L2_TUNER_MODE_STEREO; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + if (mode & V4L2_TUNER_SUB_LANG2) + selected = V4L2_TUNER_MODE_LANG1_LANG2; + else if (mode & V4L2_TUNER_SUB_STEREO) + selected = V4L2_TUNER_MODE_STEREO; + } + desc->setaudmode(chip, selected); /* schedule next check */ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); @@ -358,24 +373,25 @@ static int chip_thread(void *data) #define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */ #define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */ -static int tda9840_getmode(struct CHIPSTATE *chip) +static int tda9840_getrxsubchans(struct CHIPSTATE *chip) { struct v4l2_subdev *sd = &chip->sd; int val, mode; val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; + mode = V4L2_TUNER_SUB_MONO; if (val & TDA9840_DS_DUAL) - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; if (val & TDA9840_ST_STEREO) - mode |= V4L2_TUNER_MODE_STEREO; + mode = V4L2_TUNER_SUB_STEREO; - v4l2_dbg(1, debug, sd, "tda9840_getmode(): raw chip read: %d, return: %d\n", + v4l2_dbg(1, debug, sd, + "tda9840_getrxsubchans(): raw chip read: %d, return: %d\n", val, mode); return mode; } -static void tda9840_setmode(struct CHIPSTATE *chip, int mode) +static void tda9840_setaudmode(struct CHIPSTATE *chip, int mode) { int update = 1; int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e; @@ -393,6 +409,9 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode) case V4L2_TUNER_MODE_LANG2: t |= TDA9840_DUALB; break; + case V4L2_TUNER_MODE_LANG1_LANG2: + t |= TDA9840_DUALAB; + break; default: update = 0; } @@ -477,6 +496,7 @@ static int tda9840_checkit(struct CHIPSTATE *chip) /* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */ /* Common to TDA9855 and TDA9850: */ #define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */ +#define TDA985x_MONOSAP 2<<6 /* Selects Mono on left, SAP on right */ #define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ #define TDA985x_MONO 0 /* Forces Mono output */ #define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */ @@ -513,18 +533,22 @@ static int tda9855_volume(int val) { return val/0x2e8+0x27; } static int tda9855_bass(int val) { return val/0xccc+0x06; } static int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; } -static int tda985x_getmode(struct CHIPSTATE *chip) +static int tda985x_getrxsubchans(struct CHIPSTATE *chip) { - int mode; + int mode, val; - mode = ((TDA985x_STP | TDA985x_SAPP) & - chip_read(chip)) >> 4; /* Add mono mode regardless of SAP and stereo */ /* Allows forced mono */ - return mode | V4L2_TUNER_MODE_MONO; + mode = V4L2_TUNER_SUB_MONO; + val = chip_read(chip); + if (val & TDA985x_STP) + mode = V4L2_TUNER_SUB_STEREO; + if (val & TDA985x_SAPP) + mode |= V4L2_TUNER_SUB_SAP; + return mode; } -static void tda985x_setmode(struct CHIPSTATE *chip, int mode) +static void tda985x_setaudmode(struct CHIPSTATE *chip, int mode) { int update = 1; int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f; @@ -534,11 +558,15 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode) c6 |= TDA985x_MONO; break; case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: c6 |= TDA985x_STEREO; break; - case V4L2_TUNER_MODE_LANG1: + case V4L2_TUNER_MODE_SAP: c6 |= TDA985x_SAP; break; + case V4L2_TUNER_MODE_LANG1_LANG2: + c6 |= TDA985x_MONOSAP; + break; default: update = 0; } @@ -583,9 +611,10 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode) #define TDA9873_TR_MASK (7 << 2) #define TDA9873_TR_MONO 4 #define TDA9873_TR_STEREO 1 << 4 -#define TDA9873_TR_REVERSE (1 << 3) & (1 << 2) +#define TDA9873_TR_REVERSE ((1 << 3) | (1 << 2)) #define TDA9873_TR_DUALA 1 << 2 #define TDA9873_TR_DUALB 1 << 3 +#define TDA9873_TR_DUALAB 0 /* output level controls * B5: output level switch (0 = reduced gain, 1 = normal gain) @@ -653,46 +682,51 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode) #define TDA9873_MOUT_DUALA 0 #define TDA9873_MOUT_DUALB 1 << 3 #define TDA9873_MOUT_ST 1 << 4 -#define TDA9873_MOUT_EXTM (1 << 4 ) & (1 << 3) +#define TDA9873_MOUT_EXTM ((1 << 4) | (1 << 3)) #define TDA9873_MOUT_EXTL 1 << 5 -#define TDA9873_MOUT_EXTR (1 << 5 ) & (1 << 3) -#define TDA9873_MOUT_EXTLR (1 << 5 ) & (1 << 4) -#define TDA9873_MOUT_MUTE (1 << 5 ) & (1 << 4) & (1 << 3) +#define TDA9873_MOUT_EXTR ((1 << 5) | (1 << 3)) +#define TDA9873_MOUT_EXTLR ((1 << 5) | (1 << 4)) +#define TDA9873_MOUT_MUTE ((1 << 5) | (1 << 4) | (1 << 3)) /* Status bits: (chip read) */ #define TDA9873_PONR 0 /* Power-on reset detected if = 1 */ #define TDA9873_STEREO 2 /* Stereo sound is identified */ #define TDA9873_DUAL 4 /* Dual sound is identified */ -static int tda9873_getmode(struct CHIPSTATE *chip) +static int tda9873_getrxsubchans(struct CHIPSTATE *chip) { struct v4l2_subdev *sd = &chip->sd; int val,mode; val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; + mode = V4L2_TUNER_SUB_MONO; if (val & TDA9873_STEREO) - mode |= V4L2_TUNER_MODE_STEREO; + mode = V4L2_TUNER_SUB_STEREO; if (val & TDA9873_DUAL) - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - v4l2_dbg(1, debug, sd, "tda9873_getmode(): raw chip read: %d, return: %d\n", + mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + v4l2_dbg(1, debug, sd, + "tda9873_getrxsubchans(): raw chip read: %d, return: %d\n", val, mode); return mode; } -static void tda9873_setmode(struct CHIPSTATE *chip, int mode) +static void tda9873_setaudmode(struct CHIPSTATE *chip, int mode) { struct v4l2_subdev *sd = &chip->sd; int sw_data = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK; /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - v4l2_dbg(1, debug, sd, "tda9873_setmode(): external input\n"); + v4l2_dbg(1, debug, sd, + "tda9873_setaudmode(): external input\n"); return; } - v4l2_dbg(1, debug, sd, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - v4l2_dbg(1, debug, sd, "tda9873_setmode(): sw_data = %d\n", sw_data); + v4l2_dbg(1, debug, sd, + "tda9873_setaudmode(): chip->shadow.bytes[%d] = %d\n", + TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); + v4l2_dbg(1, debug, sd, "tda9873_setaudmode(): sw_data = %d\n", + sw_data); switch (mode) { case V4L2_TUNER_MODE_MONO: @@ -707,13 +741,16 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) case V4L2_TUNER_MODE_LANG2: sw_data |= TDA9873_TR_DUALB; break; + case V4L2_TUNER_MODE_LANG1_LANG2: + sw_data |= TDA9873_TR_DUALAB; + break; default: - chip->mode = 0; return; } chip_write(chip, TDA9873_SW, sw_data); - v4l2_dbg(1, debug, sd, "tda9873_setmode(): req. mode %d; chip_write: %d\n", + v4l2_dbg(1, debug, sd, + "tda9873_setaudmode(): req. mode %d; chip_write: %d\n", mode, sw_data); } @@ -859,13 +896,13 @@ static int tda9874a_setup(struct CHIPSTATE *chip) return 1; } -static int tda9874a_getmode(struct CHIPSTATE *chip) +static int tda9874a_getrxsubchans(struct CHIPSTATE *chip) { struct v4l2_subdev *sd = &chip->sd; int dsr,nsr,mode; int necr; /* just for debugging */ - mode = V4L2_TUNER_MODE_MONO; + mode = V4L2_TUNER_SUB_MONO; if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR))) return mode; @@ -888,22 +925,23 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) * external 4052 multiplexer in audio_hook(). */ if(nsr & 0x02) /* NSR.S/MB=1 */ - mode |= V4L2_TUNER_MODE_STEREO; + mode = V4L2_TUNER_SUB_STEREO; if(nsr & 0x01) /* NSR.D/SB=1 */ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } else { if(dsr & 0x02) /* DSR.IDSTE=1 */ - mode |= V4L2_TUNER_MODE_STEREO; + mode = V4L2_TUNER_SUB_STEREO; if(dsr & 0x04) /* DSR.IDDUA=1 */ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } - v4l2_dbg(1, debug, sd, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + v4l2_dbg(1, debug, sd, + "tda9874a_getrxsubchans(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", dsr, nsr, necr, mode); return mode; } -static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) +static void tda9874a_setaudmode(struct CHIPSTATE *chip, int mode) { struct v4l2_subdev *sd = &chip->sd; @@ -939,14 +977,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) aosr = 0xa0; /* auto-select, dual B/B */ mdacosr = (tda9874a_mode) ? 0x83:0x81; break; + case V4L2_TUNER_MODE_LANG1_LANG2: + aosr = 0x00; /* always route L to L and R to R */ + mdacosr = (tda9874a_mode) ? 0x82:0x80; + break; default: - chip->mode = 0; return; } chip_write(chip, TDA9874A_AOSR, aosr); chip_write(chip, TDA9874A_MDACOSR, mdacosr); - v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + v4l2_dbg(1, debug, sd, + "tda9874a_setaudmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", mode, aosr, mdacosr); } else { /* dic == 0x07 */ @@ -974,14 +1016,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) fmmr = 0x02; /* dual */ aosr = 0x20; /* dual B/B */ break; + case V4L2_TUNER_MODE_LANG1_LANG2: + fmmr = 0x02; /* dual */ + aosr = 0x00; /* dual A/B */ + break; default: - chip->mode = 0; return; } chip_write(chip, TDA9874A_FMMR, fmmr); chip_write(chip, TDA9874A_AOSR, aosr); - v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + v4l2_dbg(1, debug, sd, + "tda9874a_setaudmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", mode, fmmr, aosr); } } @@ -1226,25 +1272,33 @@ static int tea6320_initialize(struct CHIPSTATE * chip) static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; } static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; } -static void tda8425_setmode(struct CHIPSTATE *chip, int mode) +static void tda8425_setaudmode(struct CHIPSTATE *chip, int mode) { int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1; - if (mode & V4L2_TUNER_MODE_LANG1) { + switch (mode) { + case V4L2_TUNER_MODE_LANG1: s1 |= TDA8425_S1_ML_SOUND_A; s1 |= TDA8425_S1_STEREO_PSEUDO; - - } else if (mode & V4L2_TUNER_MODE_LANG2) { + break; + case V4L2_TUNER_MODE_LANG2: s1 |= TDA8425_S1_ML_SOUND_B; s1 |= TDA8425_S1_STEREO_PSEUDO; - - } else { + break; + case V4L2_TUNER_MODE_LANG1_LANG2: s1 |= TDA8425_S1_ML_STEREO; - - if (mode & V4L2_TUNER_MODE_MONO) - s1 |= TDA8425_S1_STEREO_MONO; - if (mode & V4L2_TUNER_MODE_STEREO) - s1 |= TDA8425_S1_STEREO_SPATIAL; + s1 |= TDA8425_S1_STEREO_LINEAR; + break; + case V4L2_TUNER_MODE_MONO: + s1 |= TDA8425_S1_ML_STEREO; + s1 |= TDA8425_S1_STEREO_MONO; + break; + case V4L2_TUNER_MODE_STEREO: + s1 |= TDA8425_S1_ML_STEREO; + s1 |= TDA8425_S1_STEREO_SPATIAL; + break; + default: + return; } chip_write(chip,TDA8425_S1,s1); } @@ -1297,18 +1351,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) * stereo L L * BIL H L */ -static int ta8874z_getmode(struct CHIPSTATE *chip) +static int ta8874z_getrxsubchans(struct CHIPSTATE *chip) { int val, mode; val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; + mode = V4L2_TUNER_SUB_MONO; if (val & TA8874Z_B1){ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + mode |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; }else if (!(val & TA8874Z_B0)){ - mode |= V4L2_TUNER_MODE_STEREO; + mode = V4L2_TUNER_SUB_STEREO; } - /* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ + /* v4l2_dbg(1, debug, &chip->sd, + "ta8874z_getrxsubchans(): raw chip read: 0x%02x, return: 0x%02x\n", + val, mode); */ return mode; } @@ -1316,14 +1372,15 @@ static audiocmd ta8874z_stereo = { 2, {0, TA8874Z_SEPARATION_DEFAULT}}; static audiocmd ta8874z_mono = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}}; static audiocmd ta8874z_main = {2, { 0, TA8874Z_SEPARATION_DEFAULT}}; static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}}; +static audiocmd ta8874z_both = {2, { TA8874Z_MODE_MAIN | TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}}; -static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) +static void ta8874z_setaudmode(struct CHIPSTATE *chip, int mode) { struct v4l2_subdev *sd = &chip->sd; int update = 1; audiocmd *t = NULL; - v4l2_dbg(1, debug, sd, "ta8874z_setmode(): mode: 0x%02x\n", mode); + v4l2_dbg(1, debug, sd, "ta8874z_setaudmode(): mode: 0x%02x\n", mode); switch(mode){ case V4L2_TUNER_MODE_MONO: @@ -1338,6 +1395,9 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) case V4L2_TUNER_MODE_LANG2: t = &ta8874z_sub; break; + case V4L2_TUNER_MODE_LANG1_LANG2: + t = &ta8874z_both; + break; default: update = 0; } @@ -1394,8 +1454,8 @@ static struct CHIPDESC chiplist[] = { /* callbacks */ .checkit = tda9840_checkit, - .getmode = tda9840_getmode, - .setmode = tda9840_setmode, + .getrxsubchans = tda9840_getrxsubchans, + .setaudmode = tda9840_setaudmode, .init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN /* ,TDA9840_SW, TDA9840_MONO */} } @@ -1410,8 +1470,8 @@ static struct CHIPDESC chiplist[] = { /* callbacks */ .checkit = tda9873_checkit, - .getmode = tda9873_getmode, - .setmode = tda9873_setmode, + .getrxsubchans = tda9873_getrxsubchans, + .setaudmode = tda9873_setaudmode, .init = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } }, .inputreg = TDA9873_SW, @@ -1430,8 +1490,8 @@ static struct CHIPDESC chiplist[] = { /* callbacks */ .initialize = tda9874a_initialize, .checkit = tda9874a_checkit, - .getmode = tda9874a_getmode, - .setmode = tda9874a_setmode, + .getrxsubchans = tda9874a_getrxsubchans, + .setaudmode = tda9874a_setaudmode, }, { .name = "tda9875", @@ -1460,8 +1520,8 @@ static struct CHIPDESC chiplist[] = { .addr_hi = I2C_ADDR_TDA985x_H >> 1, .registers = 11, - .getmode = tda985x_getmode, - .setmode = tda985x_setmode, + .getrxsubchans = tda985x_getrxsubchans, + .setaudmode = tda985x_setaudmode, .init = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } } }, @@ -1482,8 +1542,8 @@ static struct CHIPDESC chiplist[] = { .volfunc = tda9855_volume, .bassfunc = tda9855_bass, .treblefunc = tda9855_treble, - .getmode = tda985x_getmode, - .setmode = tda985x_setmode, + .getrxsubchans = tda985x_getrxsubchans, + .setaudmode = tda985x_setaudmode, .init = { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2, TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT, @@ -1564,7 +1624,7 @@ static struct CHIPDESC chiplist[] = { .volfunc = tda8425_shift10, .bassfunc = tda8425_shift12, .treblefunc = tda8425_shift12, - .setmode = tda8425_setmode, + .setaudmode = tda8425_setaudmode, .inputreg = TDA8425_S1, .inputmap = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 }, @@ -1593,11 +1653,10 @@ static struct CHIPDESC chiplist[] = { .addr_lo = I2C_ADDR_TDA9840 >> 1, .addr_hi = I2C_ADDR_TDA9840 >> 1, .registers = 2, - .flags = CHIP_NEED_CHECKMODE, /* callbacks */ - .getmode = ta8874z_getmode, - .setmode = ta8874z_setmode, + .getrxsubchans = ta8874z_getrxsubchans, + .setaudmode = ta8874z_setaudmode, .init = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}}, }, @@ -1736,7 +1795,6 @@ static int tvaudio_s_radio(struct v4l2_subdev *sd) struct CHIPSTATE *chip = to_state(sd); chip->radio = 1; - chip->watch_stereo = 0; /* del_timer(&chip->wt); */ return 0; } @@ -1793,9 +1851,8 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) { struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; - int mode = 0; - if (!desc->setmode) + if (!desc->setaudmode) return 0; if (chip->radio) return 0; @@ -1805,22 +1862,18 @@ static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1: case V4L2_TUNER_MODE_LANG2: - mode = vt->audmode; - break; case V4L2_TUNER_MODE_LANG1_LANG2: - mode = V4L2_TUNER_MODE_STEREO; break; default: return -EINVAL; } chip->audmode = vt->audmode; - if (mode) { - chip->watch_stereo = 0; - /* del_timer(&chip->wt); */ - chip->mode = mode; - desc->setmode(chip, mode); - } + if (chip->thread) + wake_up_process(chip->thread); + else + desc->setaudmode(chip, vt->audmode); + return 0; } @@ -1828,30 +1881,17 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) { struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; - int mode = V4L2_TUNER_MODE_MONO; - if (!desc->getmode) + if (!desc->getrxsubchans) return 0; if (chip->radio) return 0; vt->audmode = chip->audmode; - vt->rxsubchans = 0; + vt->rxsubchans = desc->getrxsubchans(chip); vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - mode = desc->getmode(chip); - - if (mode & V4L2_TUNER_MODE_MONO) - vt->rxsubchans |= V4L2_TUNER_SUB_MONO; - if (mode & V4L2_TUNER_MODE_STEREO) - vt->rxsubchans |= V4L2_TUNER_SUB_STEREO; - /* Note: for SAP it should be mono/lang2 or stereo/lang2. - When this module is converted fully to v4l2, then this - should change for those chips that can detect SAP. */ - if (mode & V4L2_TUNER_MODE_LANG1) - vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; return 0; } @@ -1868,9 +1908,7 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; - chip->mode = 0; /* automatic */ - - /* For chips that provide getmode and setmode, and doesn't + /* For chips that provide getrxsubchans and setaudmode, and doesn't automatically follows the stereo carrier, a kthread is created to set the audio standard. In this case, when then the video channel is changed, tvaudio starts on MONO mode. @@ -1879,9 +1917,8 @@ static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr audio carrier. */ if (chip->thread) { - desc->setmode(chip, V4L2_TUNER_MODE_MONO); - if (chip->prevmode != V4L2_TUNER_MODE_MONO) - chip->prevmode = -1; /* reset previous mode */ + desc->setaudmode(chip, V4L2_TUNER_MODE_MONO); + chip->prevmode = -1; /* reset previous mode */ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); } return 0; @@ -2023,7 +2060,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * chip->thread = NULL; init_timer(&chip->wt); if (desc->flags & CHIP_NEED_CHECKMODE) { - if (!desc->getmode || !desc->setmode) { + if (!desc->getrxsubchans || !desc->setaudmode) { /* This shouldn't be happen. Warn user, but keep working without kthread */ diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index b7867427e5c4..a751b6c146fd 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -61,13 +61,20 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) int rc; buffer[0] = addr; - if (1 != (rc = i2c_master_send(c, buffer, 1))) - v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc); + + rc = i2c_master_send(c, buffer, 1); + if (rc < 0) { + v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc); + return rc; + } msleep(10); - if (1 != (rc = i2c_master_recv(c, buffer, 1))) - v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc); + rc = i2c_master_recv(c, buffer, 1); + if (rc < 0) { + v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc); + return rc; + } v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]); @@ -250,7 +257,7 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd) int opmode = 0; struct tvp5150 *decoder = to_tvp5150(sd); int input = 0; - unsigned char val; + int val; if ((decoder->output & TVP5150_BLACK_SCREEN) || !decoder->enable) input = 8; @@ -279,6 +286,11 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd) * For Composite and TV, it should be the reverse */ val = tvp5150_read(sd, TVP5150_MISC_CTL); + if (val < 0) { + v4l2_err(sd, "%s: failed with error = %d\n", __func__, val); + return; + } + if (decoder->input == TVP5150_SVIDEO) val = (val & ~0x40) | 0x10; else @@ -676,6 +688,7 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd, v4l2_std_id std = decoder->norm; u8 reg; int pos, type = 0; + int i, ret = 0; if (std == V4L2_STD_ALL) { v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); @@ -690,13 +703,17 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd, reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI; - pos = tvp5150_read(sd, reg) & 0x0f; - if (pos < 0x0f) - type = regs[pos].type.vbi_type; - - pos = tvp5150_read(sd, reg + 1) & 0x0f; - if (pos < 0x0f) - type |= regs[pos].type.vbi_type; + for (i = 0; i <= 1; i++) { + ret = tvp5150_read(sd, reg + i); + if (ret < 0) { + v4l2_err(sd, "%s: failed with error = %d\n", + __func__, ret); + return 0; + } + pos = ret & 0x0f; + if (pos < 0x0f) + type |= regs[pos].type.vbi_type; + } return type; } @@ -1031,13 +1048,21 @@ static int tvp5150_g_chip_ident(struct v4l2_subdev *sd, #ifdef CONFIG_VIDEO_ADV_DEBUG static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { + int res; + struct i2c_client *client = v4l2_get_subdevdata(sd); if (!v4l2_chip_match_i2c_client(client, ®->match)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - reg->val = tvp5150_read(sd, reg->reg & 0xff); + res = tvp5150_read(sd, reg->reg & 0xff); + if (res < 0) { + v4l2_err(sd, "%s: failed with error = %d\n", __func__, res); + return res; + } + + reg->val = res; reg->size = 1; return 0; } @@ -1126,7 +1151,8 @@ static int tvp5150_probe(struct i2c_client *c, { struct tvp5150 *core; struct v4l2_subdev *sd; - u8 msb_id, lsb_id, msb_rom, lsb_rom; + int tvp5150_id[4]; + int i, res; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(c->adapter, @@ -1139,26 +1165,37 @@ static int tvp5150_probe(struct i2c_client *c, } sd = &core->sd; v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); + + /* + * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID, + * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER + */ + for (i = 0; i < 4; i++) { + res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i); + if (res < 0) + goto free_core; + tvp5150_id[i] = res; + } + v4l_info(c, "chip found @ 0x%02x (%s)\n", c->addr << 1, c->adapter->name); - msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID); - lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID); - msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER); - lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER); - - if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */ - v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id); + if (tvp5150_id[2] == 4 && tvp5150_id[3] == 0) { /* Is TVP5150AM1 */ + v4l2_info(sd, "tvp%02x%02xam1 detected.\n", + tvp5150_id[0], tvp5150_id[1]); /* ITU-T BT.656.4 timing */ tvp5150_write(sd, TVP5150_REV_SELECT, 0); } else { - if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */ - v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id); + /* Is TVP5150A */ + if (tvp5150_id[2] == 3 || tvp5150_id[3] == 0x21) { + v4l2_info(sd, "tvp%02x%02xa detected.\n", + tvp5150_id[2], tvp5150_id[3]); } else { v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n", - msb_id, lsb_id); - v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom); + tvp5150_id[2], tvp5150_id[3]); + v4l2_info(sd, "*** Rom ver is %d.%d\n", + tvp5150_id[2], tvp5150_id[3]); } } @@ -1177,11 +1214,9 @@ static int tvp5150_probe(struct i2c_client *c, V4L2_CID_HUE, -128, 127, 1, 0); sd->ctrl_handler = &core->hdl; if (core->hdl.error) { - int err = core->hdl.error; - + res = core->hdl.error; v4l2_ctrl_handler_free(&core->hdl); - kfree(core); - return err; + goto free_core; } v4l2_ctrl_handler_setup(&core->hdl); @@ -1197,6 +1232,10 @@ static int tvp5150_probe(struct i2c_client *c, if (debug > 1) tvp5150_log_status(sd); return 0; + +free_core: + kfree(core); + return res; } static int tvp5150_remove(struct i2c_client *c) diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 8768efb8508a..9f53eacb66e3 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -699,11 +699,9 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, struct tw9910_priv *priv = to_tw9910(client); if (!priv->scale) { - int ret; - u32 width = 640, height = 480; - ret = tw9910_set_frame(sd, &width, &height); - if (ret < 0) - return ret; + priv->scale = tw9910_select_norm(priv->norm, 640, 480); + if (!priv->scale) + return -EINVAL; } mf->width = priv->scale->width; diff --git a/drivers/media/video/uvc/Kconfig b/drivers/media/video/uvc/Kconfig index 6c197da531b2..541c9f1e4c6a 100644 --- a/drivers/media/video/uvc/Kconfig +++ b/drivers/media/video/uvc/Kconfig @@ -10,6 +10,7 @@ config USB_VIDEO_CLASS config USB_VIDEO_CLASS_INPUT_EVDEV bool "UVC input events device support" default y + depends on USB_VIDEO_CLASS depends on USB_VIDEO_CLASS=INPUT || INPUT=y ---help--- This option makes USB Video Class devices register an input device diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index af26bbe6f76e..f7061a5ef1d2 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -2083,7 +2083,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) /* Walk the entities list and instantiate controls */ list_for_each_entry(entity, &dev->entities, list) { struct uvc_control *ctrl; - unsigned int bControlSize = 0, ncontrols = 0; + unsigned int bControlSize = 0, ncontrols; __u8 *bmControls = NULL; if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) { @@ -2101,8 +2101,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) uvc_ctrl_prune_entity(dev, entity); /* Count supported controls and allocate the controls array */ - for (i = 0; i < bControlSize; ++i) - ncontrols += hweight8(bmControls[i]); + ncontrols = memweight(bmControls, bControlSize); if (ncontrols == 0) continue; diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 759bef8897e9..f00db3060e0e 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -1051,7 +1051,7 @@ static long uvc_v4l2_ioctl(struct file *file, { if (uvc_trace_param & UVC_TRACE_IOCTL) { uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl("); - v4l_printk_ioctl(cmd); + v4l_printk_ioctl(NULL, cmd); printk(")\n"); } diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index b76b0ac0958f..7ac4347ca09e 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -1188,7 +1188,11 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream, u8 *mem; int len, ret; - if (urb->actual_length == 0) + /* + * Ignore ZLPs if they're not part of a frame, otherwise process them + * to trigger the end of payload detection. + */ + if (urb->actual_length == 0 && stream->bulk.header_size == 0) return; mem = urb->transfer_buffer; @@ -1594,7 +1598,7 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); if (psize >= bandwidth && psize <= best_psize) { - altsetting = i; + altsetting = alts->desc.bAlternateSetting; best_psize = psize; best_ep = ep; } diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 5327ad3a6390..9ebd5c540d10 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -327,7 +327,7 @@ struct v4l2_buffer32 { compat_caddr_t planes; } m; __u32 length; - __u32 input; + __u32 reserved2; __u32 reserved; }; @@ -387,8 +387,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user get_user(kp->index, &up->index) || get_user(kp->type, &up->type) || get_user(kp->flags, &up->flags) || - get_user(kp->memory, &up->memory) || - get_user(kp->input, &up->input)) + get_user(kp->memory, &up->memory)) return -EFAULT; if (V4L2_TYPE_IS_OUTPUT(kp->type)) @@ -472,8 +471,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user put_user(kp->index, &up->index) || put_user(kp->type, &up->type) || put_user(kp->flags, &up->flags) || - put_user(kp->memory, &up->memory) || - put_user(kp->input, &up->input)) + put_user(kp->memory, &up->memory)) return -EFAULT; if (put_user(kp->bytesused, &up->bytesused) || @@ -482,6 +480,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) || copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) || put_user(kp->sequence, &up->sequence) || + put_user(kp->reserved2, &up->reserved2) || put_user(kp->reserved, &up->reserved)) return -EFAULT; @@ -1026,6 +1025,7 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_ENUM_DV_TIMINGS: case VIDIOC_QUERY_DV_TIMINGS: case VIDIOC_DV_TIMINGS_CAP: + case VIDIOC_ENUM_FREQ_BANDS: ret = do_video_ioctl(file, cmd, arg); break; diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 9abd9abd4502..b6a2ee71e5c3 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -755,6 +755,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_HUE_AUTO: case V4L2_CID_CHROMA_AGC: case V4L2_CID_COLOR_KILLER: + case V4L2_CID_AUTOBRIGHTNESS: case V4L2_CID_MPEG_AUDIO_MUTE: case V4L2_CID_MPEG_VIDEO_MUTE: case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: @@ -2120,7 +2121,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, /* First zero the helper field in the master control references */ for (i = 0; i < cs->count; i++) - helpers[i].mref->helper = 0; + helpers[i].mref->helper = NULL; for (i = 0, h = helpers; i < cs->count; i++, h++) { struct v4l2_ctrl_ref *mref = h->mref; diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 83dbb2ddff10..07aeafca9eaa 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -46,6 +46,29 @@ static ssize_t show_index(struct device *cd, return sprintf(buf, "%i\n", vdev->index); } +static ssize_t show_debug(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(cd); + + return sprintf(buf, "%i\n", vdev->debug); +} + +static ssize_t set_debug(struct device *cd, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct video_device *vdev = to_video_device(cd); + int res = 0; + u16 value; + + res = kstrtou16(buf, 0, &value); + if (res) + return res; + + vdev->debug = value; + return len; +} + static ssize_t show_name(struct device *cd, struct device_attribute *attr, char *buf) { @@ -56,6 +79,7 @@ static ssize_t show_name(struct device *cd, static struct device_attribute video_device_attrs[] = { __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(debug, 0644, show_debug, set_debug), __ATTR(index, S_IRUGO, show_index, NULL), __ATTR_NULL }; @@ -281,6 +305,9 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf, ret = vdev->fops->read(filp, buf, sz, off); if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags)) mutex_unlock(vdev->lock); + if (vdev->debug) + printk(KERN_DEBUG "%s: read: %zd (%d)\n", + video_device_node_name(vdev), sz, ret); return ret; } @@ -299,6 +326,9 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, ret = vdev->fops->write(filp, buf, sz, off); if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags)) mutex_unlock(vdev->lock); + if (vdev->debug) + printk(KERN_DEBUG "%s: write: %zd (%d)\n", + video_device_node_name(vdev), sz, ret); return ret; } @@ -315,6 +345,9 @@ static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) ret = vdev->fops->poll(filp, poll); if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags)) mutex_unlock(vdev->lock); + if (vdev->debug) + printk(KERN_DEBUG "%s: poll: %08x\n", + video_device_node_name(vdev), ret); return ret; } @@ -324,20 +357,14 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) int ret = -ENODEV; if (vdev->fops->unlocked_ioctl) { - bool locked = false; + struct mutex *lock = v4l2_ioctl_get_lock(vdev, cmd); - if (vdev->lock) { - /* always lock unless the cmd is marked as "don't use lock" */ - locked = !v4l2_is_known_ioctl(cmd) || - !test_bit(_IOC_NR(cmd), vdev->disable_locking); - - if (locked && mutex_lock_interruptible(vdev->lock)) - return -ERESTARTSYS; - } + if (lock && mutex_lock_interruptible(lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); - if (locked) - mutex_unlock(vdev->lock); + if (lock) + mutex_unlock(lock); } else if (vdev->fops->ioctl) { /* This code path is a replacement for the BKL. It is a major * hack but it will have to do for those drivers that are not @@ -385,12 +412,17 @@ static unsigned long v4l2_get_unmapped_area(struct file *filp, unsigned long flags) { struct video_device *vdev = video_devdata(filp); + int ret; if (!vdev->fops->get_unmapped_area) return -ENOSYS; if (!video_is_registered(vdev)) return -ENODEV; - return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); + ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); + if (vdev->debug) + printk(KERN_DEBUG "%s: get_unmapped_area (%d)\n", + video_device_node_name(vdev), ret); + return ret; } #endif @@ -408,6 +440,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) ret = vdev->fops->mmap(filp, vm); if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags)) mutex_unlock(vdev->lock); + if (vdev->debug) + printk(KERN_DEBUG "%s: mmap (%d)\n", + video_device_node_name(vdev), ret); return ret; } @@ -443,6 +478,9 @@ static int v4l2_open(struct inode *inode, struct file *filp) } err: + if (vdev->debug) + printk(KERN_DEBUG "%s: open (%d)\n", + video_device_node_name(vdev), ret); /* decrease the refcount in case of an error */ if (ret) video_put(vdev); @@ -462,6 +500,9 @@ static int v4l2_release(struct inode *inode, struct file *filp) if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags)) mutex_unlock(vdev->lock); } + if (vdev->debug) + printk(KERN_DEBUG "%s: release\n", + video_device_node_name(vdev)); /* decrease the refcount unconditionally since the release() return value is ignored. */ video_put(vdev); @@ -656,7 +697,8 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd); SET_VALID_IOCTL(ops, VIDIOC_DECODER_CMD, vidioc_decoder_cmd); SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd); - if (ops->vidioc_g_parm || vdev->vfl_type == VFL_TYPE_GRABBER) + if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER && + (ops->vidioc_g_std || vdev->tvnorms))) set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner); @@ -681,12 +723,15 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings); + SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap); /* yes, really vidioc_subscribe_event */ SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event); SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event); SET_VALID_IOCTL(ops, VIDIOC_UNSUBSCRIBE_EVENT, vidioc_unsubscribe_event); SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs); SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf); + if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator) + set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls); bitmap_andnot(vdev->valid_ioctls, valid_ioctls, vdev->valid_ioctls, BASE_VIDIOC_PRIVATE); } diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index d7fa8962d8b3..c3b7b5f59b32 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -27,27 +27,7 @@ #include <media/v4l2-event.h> #include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> - -#define dbgarg(cmd, fmt, arg...) \ - do { \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ - printk(KERN_DEBUG "%s: ", vfd->name); \ - v4l_printk_ioctl(cmd); \ - printk(" " fmt, ## arg); \ - } \ - } while (0) - -#define dbgarg2(fmt, arg...) \ - do { \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ - printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\ - } while (0) - -#define dbgarg3(fmt, arg...) \ - do { \ - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ - printk(KERN_CONT "%s: " fmt, vfd->name, ## arg);\ - } while (0) +#include <media/videobuf2-core.h> /* Zero out the end of the struct pointed to by p. Everything after, but * not including, the specified field is cleared. */ @@ -183,207 +163,507 @@ static const char *v4l2_memory_names[] = { /* ------------------------------------------------------------------ */ /* debug help functions */ -struct v4l2_ioctl_info { - unsigned int ioctl; - u16 flags; - const char * const name; -}; +static void v4l_print_querycap(const void *arg, bool write_only) +{ + const struct v4l2_capability *p = arg; -/* This control needs a priority check */ -#define INFO_FL_PRIO (1 << 0) -/* This control can be valid if the filehandle passes a control handler. */ -#define INFO_FL_CTRL (1 << 1) + pr_cont("driver=%s, card=%s, bus=%s, version=0x%08x, " + "capabilities=0x%08x, device_caps=0x%08x\n", + p->driver, p->card, p->bus_info, + p->version, p->capabilities, p->device_caps); +} -#define IOCTL_INFO(_ioctl, _flags) [_IOC_NR(_ioctl)] = { \ - .ioctl = _ioctl, \ - .flags = _flags, \ - .name = #_ioctl, \ +static void v4l_print_enuminput(const void *arg, bool write_only) +{ + const struct v4l2_input *p = arg; + + pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, tuner=%u, " + "std=0x%08Lx, status=0x%x, capabilities=0x%x\n", + p->index, p->name, p->type, p->audioset, p->tuner, + (unsigned long long)p->std, p->status, p->capabilities); } -static struct v4l2_ioctl_info v4l2_ioctls[] = { - IOCTL_INFO(VIDIOC_QUERYCAP, 0), - IOCTL_INFO(VIDIOC_ENUM_FMT, 0), - IOCTL_INFO(VIDIOC_G_FMT, 0), - IOCTL_INFO(VIDIOC_S_FMT, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_REQBUFS, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_QUERYBUF, 0), - IOCTL_INFO(VIDIOC_G_FBUF, 0), - IOCTL_INFO(VIDIOC_S_FBUF, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_OVERLAY, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_QBUF, 0), - IOCTL_INFO(VIDIOC_DQBUF, 0), - IOCTL_INFO(VIDIOC_STREAMON, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_STREAMOFF, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_PARM, 0), - IOCTL_INFO(VIDIOC_S_PARM, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_STD, 0), - IOCTL_INFO(VIDIOC_S_STD, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_ENUMSTD, 0), - IOCTL_INFO(VIDIOC_ENUMINPUT, 0), - IOCTL_INFO(VIDIOC_G_CTRL, INFO_FL_CTRL), - IOCTL_INFO(VIDIOC_S_CTRL, INFO_FL_PRIO | INFO_FL_CTRL), - IOCTL_INFO(VIDIOC_G_TUNER, 0), - IOCTL_INFO(VIDIOC_S_TUNER, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_AUDIO, 0), - IOCTL_INFO(VIDIOC_S_AUDIO, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_QUERYCTRL, INFO_FL_CTRL), - IOCTL_INFO(VIDIOC_QUERYMENU, INFO_FL_CTRL), - IOCTL_INFO(VIDIOC_G_INPUT, 0), - IOCTL_INFO(VIDIOC_S_INPUT, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_OUTPUT, 0), - IOCTL_INFO(VIDIOC_S_OUTPUT, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_ENUMOUTPUT, 0), - IOCTL_INFO(VIDIOC_G_AUDOUT, 0), - IOCTL_INFO(VIDIOC_S_AUDOUT, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_MODULATOR, 0), - IOCTL_INFO(VIDIOC_S_MODULATOR, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_FREQUENCY, 0), - IOCTL_INFO(VIDIOC_S_FREQUENCY, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_CROPCAP, 0), - IOCTL_INFO(VIDIOC_G_CROP, 0), - IOCTL_INFO(VIDIOC_S_CROP, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_SELECTION, 0), - IOCTL_INFO(VIDIOC_S_SELECTION, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_JPEGCOMP, 0), - IOCTL_INFO(VIDIOC_S_JPEGCOMP, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_QUERYSTD, 0), - IOCTL_INFO(VIDIOC_TRY_FMT, 0), - IOCTL_INFO(VIDIOC_ENUMAUDIO, 0), - IOCTL_INFO(VIDIOC_ENUMAUDOUT, 0), - IOCTL_INFO(VIDIOC_G_PRIORITY, 0), - IOCTL_INFO(VIDIOC_S_PRIORITY, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_SLICED_VBI_CAP, 0), - IOCTL_INFO(VIDIOC_LOG_STATUS, 0), - IOCTL_INFO(VIDIOC_G_EXT_CTRLS, INFO_FL_CTRL), - IOCTL_INFO(VIDIOC_S_EXT_CTRLS, INFO_FL_PRIO | INFO_FL_CTRL), - IOCTL_INFO(VIDIOC_TRY_EXT_CTRLS, 0), - IOCTL_INFO(VIDIOC_ENUM_FRAMESIZES, 0), - IOCTL_INFO(VIDIOC_ENUM_FRAMEINTERVALS, 0), - IOCTL_INFO(VIDIOC_G_ENC_INDEX, 0), - IOCTL_INFO(VIDIOC_ENCODER_CMD, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_TRY_ENCODER_CMD, 0), - IOCTL_INFO(VIDIOC_DECODER_CMD, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_TRY_DECODER_CMD, 0), -#ifdef CONFIG_VIDEO_ADV_DEBUG - IOCTL_INFO(VIDIOC_DBG_S_REGISTER, 0), - IOCTL_INFO(VIDIOC_DBG_G_REGISTER, 0), -#endif - IOCTL_INFO(VIDIOC_DBG_G_CHIP_IDENT, 0), - IOCTL_INFO(VIDIOC_S_HW_FREQ_SEEK, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_ENUM_DV_PRESETS, 0), - IOCTL_INFO(VIDIOC_S_DV_PRESET, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_DV_PRESET, 0), - IOCTL_INFO(VIDIOC_QUERY_DV_PRESET, 0), - IOCTL_INFO(VIDIOC_S_DV_TIMINGS, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_G_DV_TIMINGS, 0), - IOCTL_INFO(VIDIOC_DQEVENT, 0), - IOCTL_INFO(VIDIOC_SUBSCRIBE_EVENT, 0), - IOCTL_INFO(VIDIOC_UNSUBSCRIBE_EVENT, 0), - IOCTL_INFO(VIDIOC_CREATE_BUFS, INFO_FL_PRIO), - IOCTL_INFO(VIDIOC_PREPARE_BUF, 0), - IOCTL_INFO(VIDIOC_ENUM_DV_TIMINGS, 0), - IOCTL_INFO(VIDIOC_QUERY_DV_TIMINGS, 0), - IOCTL_INFO(VIDIOC_DV_TIMINGS_CAP, 0), -}; -#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) +static void v4l_print_enumoutput(const void *arg, bool write_only) +{ + const struct v4l2_output *p = arg; -bool v4l2_is_known_ioctl(unsigned int cmd) + pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, " + "modulator=%u, std=0x%08Lx, capabilities=0x%x\n", + p->index, p->name, p->type, p->audioset, p->modulator, + (unsigned long long)p->std, p->capabilities); +} + +static void v4l_print_audio(const void *arg, bool write_only) { - if (_IOC_NR(cmd) >= V4L2_IOCTLS) - return false; - return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd; + const struct v4l2_audio *p = arg; + + if (write_only) + pr_cont("index=%u, mode=0x%x\n", p->index, p->mode); + else + pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n", + p->index, p->name, p->capability, p->mode); } -/* Common ioctl debug function. This function can be used by - external ioctl messages as well as internal V4L ioctl */ -void v4l_printk_ioctl(unsigned int cmd) +static void v4l_print_audioout(const void *arg, bool write_only) { - char *dir, *type; + const struct v4l2_audioout *p = arg; - switch (_IOC_TYPE(cmd)) { - case 'd': - type = "v4l2_int"; + if (write_only) + pr_cont("index=%u\n", p->index); + else + pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n", + p->index, p->name, p->capability, p->mode); +} + +static void v4l_print_fmtdesc(const void *arg, bool write_only) +{ + const struct v4l2_fmtdesc *p = arg; + + pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%s'\n", + p->index, prt_names(p->type, v4l2_type_names), + p->flags, (p->pixelformat & 0xff), + (p->pixelformat >> 8) & 0xff, + (p->pixelformat >> 16) & 0xff, + (p->pixelformat >> 24) & 0xff, + p->description); +} + +static void v4l_print_format(const void *arg, bool write_only) +{ + const struct v4l2_format *p = arg; + const struct v4l2_pix_format *pix; + const struct v4l2_pix_format_mplane *mp; + const struct v4l2_vbi_format *vbi; + const struct v4l2_sliced_vbi_format *sliced; + const struct v4l2_window *win; + const struct v4l2_clip *clip; + unsigned i; + + pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &p->fmt.pix; + pr_cont(", width=%u, height=%u, " + "pixelformat=%c%c%c%c, field=%s, " + "bytesperline=%u sizeimage=%u, colorspace=%d\n", + pix->width, pix->height, + (pix->pixelformat & 0xff), + (pix->pixelformat >> 8) & 0xff, + (pix->pixelformat >> 16) & 0xff, + (pix->pixelformat >> 24) & 0xff, + prt_names(pix->field, v4l2_field_names), + pix->bytesperline, pix->sizeimage, + pix->colorspace); break; - case 'V': - if (_IOC_NR(cmd) >= V4L2_IOCTLS) { - type = "v4l2"; - break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + mp = &p->fmt.pix_mp; + pr_cont(", width=%u, height=%u, " + "format=%c%c%c%c, field=%s, " + "colorspace=%d, num_planes=%u\n", + mp->width, mp->height, + (mp->pixelformat & 0xff), + (mp->pixelformat >> 8) & 0xff, + (mp->pixelformat >> 16) & 0xff, + (mp->pixelformat >> 24) & 0xff, + prt_names(mp->field, v4l2_field_names), + mp->colorspace, mp->num_planes); + for (i = 0; i < mp->num_planes; i++) + printk(KERN_DEBUG "plane %u: bytesperline=%u sizeimage=%u\n", i, + mp->plane_fmt[i].bytesperline, + mp->plane_fmt[i].sizeimage); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + win = &p->fmt.win; + pr_cont(", wxh=%dx%d, x,y=%d,%d, field=%s, " + "chromakey=0x%08x, bitmap=%p, " + "global_alpha=0x%02x\n", + win->w.width, win->w.height, + win->w.left, win->w.top, + prt_names(win->field, v4l2_field_names), + win->chromakey, win->bitmap, win->global_alpha); + clip = win->clips; + for (i = 0; i < win->clipcount; i++) { + printk(KERN_DEBUG "clip %u: wxh=%dx%d, x,y=%d,%d\n", + i, clip->c.width, clip->c.height, + clip->c.left, clip->c.top); + clip = clip->next; } - printk("%s", v4l2_ioctls[_IOC_NR(cmd)].name); - return; - default: - type = "unknown"; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + vbi = &p->fmt.vbi; + pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, " + "sample_format=%c%c%c%c, start=%u,%u, count=%u,%u\n", + vbi->sampling_rate, vbi->offset, + vbi->samples_per_line, + (vbi->sample_format & 0xff), + (vbi->sample_format >> 8) & 0xff, + (vbi->sample_format >> 16) & 0xff, + (vbi->sample_format >> 24) & 0xff, + vbi->start[0], vbi->start[1], + vbi->count[0], vbi->count[1]); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + sliced = &p->fmt.sliced; + pr_cont(", service_set=0x%08x, io_size=%d\n", + sliced->service_set, sliced->io_size); + for (i = 0; i < 24; i++) + printk(KERN_DEBUG "line[%02u]=0x%04x, 0x%04x\n", i, + sliced->service_lines[0][i], + sliced->service_lines[1][i]); + break; + case V4L2_BUF_TYPE_PRIVATE: + pr_cont("\n"); + break; } +} - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "*ERR*"; break; - } - printk("%s ioctl '%c', dir=%s, #%d (0x%08x)", - type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); +static void v4l_print_framebuffer(const void *arg, bool write_only) +{ + const struct v4l2_framebuffer *p = arg; + + pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, " + "height=%u, pixelformat=%c%c%c%c, " + "bytesperline=%u sizeimage=%u, colorspace=%d\n", + p->capability, p->flags, p->base, + p->fmt.width, p->fmt.height, + (p->fmt.pixelformat & 0xff), + (p->fmt.pixelformat >> 8) & 0xff, + (p->fmt.pixelformat >> 16) & 0xff, + (p->fmt.pixelformat >> 24) & 0xff, + p->fmt.bytesperline, p->fmt.sizeimage, + p->fmt.colorspace); +} + +static void v4l_print_buftype(const void *arg, bool write_only) +{ + pr_cont("type=%s\n", prt_names(*(u32 *)arg, v4l2_type_names)); +} + +static void v4l_print_modulator(const void *arg, bool write_only) +{ + const struct v4l2_modulator *p = arg; + + if (write_only) + pr_cont("index=%u, txsubchans=0x%x", p->index, p->txsubchans); + else + pr_cont("index=%u, name=%s, capability=0x%x, " + "rangelow=%u, rangehigh=%u, txsubchans=0x%x\n", + p->index, p->name, p->capability, + p->rangelow, p->rangehigh, p->txsubchans); +} + +static void v4l_print_tuner(const void *arg, bool write_only) +{ + const struct v4l2_tuner *p = arg; + + if (write_only) + pr_cont("index=%u, audmode=%u\n", p->index, p->audmode); + else + pr_cont("index=%u, name=%s, type=%u, capability=0x%x, " + "rangelow=%u, rangehigh=%u, signal=%u, afc=%d, " + "rxsubchans=0x%x, audmode=%u\n", + p->index, p->name, p->type, + p->capability, p->rangelow, + p->rangehigh, p->signal, p->afc, + p->rxsubchans, p->audmode); } -EXPORT_SYMBOL(v4l_printk_ioctl); -static void dbgbuf(unsigned int cmd, struct video_device *vfd, - struct v4l2_buffer *p) +static void v4l_print_frequency(const void *arg, bool write_only) { - struct v4l2_timecode *tc = &p->timecode; - struct v4l2_plane *plane; + const struct v4l2_frequency *p = arg; + + pr_cont("tuner=%u, type=%u, frequency=%u\n", + p->tuner, p->type, p->frequency); +} + +static void v4l_print_standard(const void *arg, bool write_only) +{ + const struct v4l2_standard *p = arg; + + pr_cont("index=%u, id=0x%Lx, name=%s, fps=%u/%u, " + "framelines=%u\n", p->index, + (unsigned long long)p->id, p->name, + p->frameperiod.numerator, + p->frameperiod.denominator, + p->framelines); +} + +static void v4l_print_std(const void *arg, bool write_only) +{ + pr_cont("std=0x%08Lx\n", *(const long long unsigned *)arg); +} + +static void v4l_print_hw_freq_seek(const void *arg, bool write_only) +{ + const struct v4l2_hw_freq_seek *p = arg; + + pr_cont("tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n", + p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing); +} + +static void v4l_print_requestbuffers(const void *arg, bool write_only) +{ + const struct v4l2_requestbuffers *p = arg; + + pr_cont("count=%d, type=%s, memory=%s\n", + p->count, + prt_names(p->type, v4l2_type_names), + prt_names(p->memory, v4l2_memory_names)); +} + +static void v4l_print_buffer(const void *arg, bool write_only) +{ + const struct v4l2_buffer *p = arg; + const struct v4l2_timecode *tc = &p->timecode; + const struct v4l2_plane *plane; int i; - dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " - "flags=0x%08d, field=%0d, sequence=%d, memory=%s\n", + pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, " + "flags=0x%08x, field=%s, sequence=%d, memory=%s", p->timestamp.tv_sec / 3600, (int)(p->timestamp.tv_sec / 60) % 60, (int)(p->timestamp.tv_sec % 60), (long)p->timestamp.tv_usec, p->index, prt_names(p->type, v4l2_type_names), - p->flags, p->field, p->sequence, - prt_names(p->memory, v4l2_memory_names)); + p->flags, prt_names(p->field, v4l2_field_names), + p->sequence, prt_names(p->memory, v4l2_memory_names)); if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) { + pr_cont("\n"); for (i = 0; i < p->length; ++i) { plane = &p->m.planes[i]; - dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x " - "offset/userptr=0x%08lx, length=%d\n", + printk(KERN_DEBUG + "plane %d: bytesused=%d, data_offset=0x%08x " + "offset/userptr=0x%lx, length=%d\n", i, plane->bytesused, plane->data_offset, plane->m.userptr, plane->length); } } else { - dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n", + pr_cont("bytesused=%d, offset/userptr=0x%lx, length=%d\n", p->bytesused, p->m.userptr, p->length); } - dbgarg2("timecode=%02d:%02d:%02d type=%d, " - "flags=0x%08d, frames=%d, userbits=0x%08x\n", + printk(KERN_DEBUG "timecode=%02d:%02d:%02d type=%d, " + "flags=0x%08x, frames=%d, userbits=0x%08x\n", tc->hours, tc->minutes, tc->seconds, tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits); } -static inline void dbgrect(struct video_device *vfd, char *s, - struct v4l2_rect *r) +static void v4l_print_create_buffers(const void *arg, bool write_only) { - dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top, - r->width, r->height); -}; + const struct v4l2_create_buffers *p = arg; + + pr_cont("index=%d, count=%d, memory=%s, ", + p->index, p->count, + prt_names(p->memory, v4l2_memory_names)); + v4l_print_format(&p->format, write_only); +} -static void dbgtimings(struct video_device *vfd, - const struct v4l2_dv_timings *p) +static void v4l_print_streamparm(const void *arg, bool write_only) { + const struct v4l2_streamparm *p = arg; + + pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); + + if (p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || + p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + const struct v4l2_captureparm *c = &p->parm.capture; + + pr_cont(", capability=0x%x, capturemode=0x%x, timeperframe=%d/%d, " + "extendedmode=%d, readbuffers=%d\n", + c->capability, c->capturemode, + c->timeperframe.numerator, c->timeperframe.denominator, + c->extendedmode, c->readbuffers); + } else if (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || + p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + const struct v4l2_outputparm *c = &p->parm.output; + + pr_cont(", capability=0x%x, outputmode=0x%x, timeperframe=%d/%d, " + "extendedmode=%d, writebuffers=%d\n", + c->capability, c->outputmode, + c->timeperframe.numerator, c->timeperframe.denominator, + c->extendedmode, c->writebuffers); + } +} + +static void v4l_print_queryctrl(const void *arg, bool write_only) +{ + const struct v4l2_queryctrl *p = arg; + + pr_cont("id=0x%x, type=%d, name=%s, min/max=%d/%d, " + "step=%d, default=%d, flags=0x%08x\n", + p->id, p->type, p->name, + p->minimum, p->maximum, + p->step, p->default_value, p->flags); +} + +static void v4l_print_querymenu(const void *arg, bool write_only) +{ + const struct v4l2_querymenu *p = arg; + + pr_cont("id=0x%x, index=%d\n", p->id, p->index); +} + +static void v4l_print_control(const void *arg, bool write_only) +{ + const struct v4l2_control *p = arg; + + pr_cont("id=0x%x, value=%d\n", p->id, p->value); +} + +static void v4l_print_ext_controls(const void *arg, bool write_only) +{ + const struct v4l2_ext_controls *p = arg; + int i; + + pr_cont("class=0x%x, count=%d, error_idx=%d", + p->ctrl_class, p->count, p->error_idx); + for (i = 0; i < p->count; i++) { + if (p->controls[i].size) + pr_cont(", id/val=0x%x/0x%x", + p->controls[i].id, p->controls[i].value); + else + pr_cont(", id/size=0x%x/%u", + p->controls[i].id, p->controls[i].size); + } + pr_cont("\n"); +} + +static void v4l_print_cropcap(const void *arg, bool write_only) +{ + const struct v4l2_cropcap *p = arg; + + pr_cont("type=%s, bounds wxh=%dx%d, x,y=%d,%d, " + "defrect wxh=%dx%d, x,y=%d,%d\n, " + "pixelaspect %d/%d\n", + prt_names(p->type, v4l2_type_names), + p->bounds.width, p->bounds.height, + p->bounds.left, p->bounds.top, + p->defrect.width, p->defrect.height, + p->defrect.left, p->defrect.top, + p->pixelaspect.numerator, p->pixelaspect.denominator); +} + +static void v4l_print_crop(const void *arg, bool write_only) +{ + const struct v4l2_crop *p = arg; + + pr_cont("type=%s, wxh=%dx%d, x,y=%d,%d\n", + prt_names(p->type, v4l2_type_names), + p->c.width, p->c.height, + p->c.left, p->c.top); +} + +static void v4l_print_selection(const void *arg, bool write_only) +{ + const struct v4l2_selection *p = arg; + + pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n", + prt_names(p->type, v4l2_type_names), + p->target, p->flags, + p->r.width, p->r.height, p->r.left, p->r.top); +} + +static void v4l_print_jpegcompression(const void *arg, bool write_only) +{ + const struct v4l2_jpegcompression *p = arg; + + pr_cont("quality=%d, APPn=%d, APP_len=%d, " + "COM_len=%d, jpeg_markers=0x%x\n", + p->quality, p->APPn, p->APP_len, + p->COM_len, p->jpeg_markers); +} + +static void v4l_print_enc_idx(const void *arg, bool write_only) +{ + const struct v4l2_enc_idx *p = arg; + + pr_cont("entries=%d, entries_cap=%d\n", + p->entries, p->entries_cap); +} + +static void v4l_print_encoder_cmd(const void *arg, bool write_only) +{ + const struct v4l2_encoder_cmd *p = arg; + + pr_cont("cmd=%d, flags=0x%x\n", + p->cmd, p->flags); +} + +static void v4l_print_decoder_cmd(const void *arg, bool write_only) +{ + const struct v4l2_decoder_cmd *p = arg; + + pr_cont("cmd=%d, flags=0x%x\n", p->cmd, p->flags); + + if (p->cmd == V4L2_DEC_CMD_START) + pr_info("speed=%d, format=%u\n", + p->start.speed, p->start.format); + else if (p->cmd == V4L2_DEC_CMD_STOP) + pr_info("pts=%llu\n", p->stop.pts); +} + +static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) +{ + const struct v4l2_dbg_chip_ident *p = arg; + + pr_cont("type=%u, ", p->match.type); + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) + pr_cont("name=%s, ", p->match.name); + else + pr_cont("addr=%u, ", p->match.addr); + pr_cont("chip_ident=%u, revision=0x%x\n", + p->ident, p->revision); +} + +static void v4l_print_dbg_register(const void *arg, bool write_only) +{ + const struct v4l2_dbg_register *p = arg; + + pr_cont("type=%u, ", p->match.type); + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) + pr_cont("name=%s, ", p->match.name); + else + pr_cont("addr=%u, ", p->match.addr); + pr_cont("reg=0x%llx, val=0x%llx\n", + p->reg, p->val); +} + +static void v4l_print_dv_enum_presets(const void *arg, bool write_only) +{ + const struct v4l2_dv_enum_preset *p = arg; + + pr_cont("index=%u, preset=%u, name=%s, width=%u, height=%u\n", + p->index, p->preset, p->name, p->width, p->height); +} + +static void v4l_print_dv_preset(const void *arg, bool write_only) +{ + const struct v4l2_dv_preset *p = arg; + + pr_cont("preset=%u\n", p->preset); +} + +static void v4l_print_dv_timings(const void *arg, bool write_only) +{ + const struct v4l2_dv_timings *p = arg; + switch (p->type) { case V4L2_DV_BT_656_1120: - dbgarg2("bt-656/1120:interlaced=%d," - " pixelclock=%lld," - " width=%d, height=%d, polarities=%x," - " hfrontporch=%d, hsync=%d," - " hbackporch=%d, vfrontporch=%d," - " vsync=%d, vbackporch=%d," - " il_vfrontporch=%d, il_vsync=%d," - " il_vbackporch=%d, standards=%x, flags=%x\n", + pr_cont("type=bt-656/1120, interlaced=%u, " + "pixelclock=%llu, " + "width=%u, height=%u, polarities=0x%x, " + "hfrontporch=%u, hsync=%u, " + "hbackporch=%u, vfrontporch=%u, " + "vsync=%u, vbackporch=%u, " + "il_vfrontporch=%u, il_vsync=%u, " + "il_vbackporch=%u, standards=0x%x, flags=0x%x\n", p->bt.interlaced, p->bt.pixelclock, p->bt.width, p->bt.height, p->bt.polarities, p->bt.hfrontporch, @@ -394,67 +674,184 @@ static void dbgtimings(struct video_device *vfd, p->bt.standards, p->bt.flags); break; default: - dbgarg2("Unknown type %d!\n", p->type); + pr_cont("type=%d\n", p->type); break; } } -static inline void v4l_print_pix_fmt(struct video_device *vfd, - struct v4l2_pix_format *fmt) +static void v4l_print_enum_dv_timings(const void *arg, bool write_only) { - dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " - "bytesperline=%d sizeimage=%d, colorspace=%d\n", - fmt->width, fmt->height, - (fmt->pixelformat & 0xff), - (fmt->pixelformat >> 8) & 0xff, - (fmt->pixelformat >> 16) & 0xff, - (fmt->pixelformat >> 24) & 0xff, - prt_names(fmt->field, v4l2_field_names), - fmt->bytesperline, fmt->sizeimage, fmt->colorspace); -}; + const struct v4l2_enum_dv_timings *p = arg; + + pr_cont("index=%u, ", p->index); + v4l_print_dv_timings(&p->timings, write_only); +} -static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd, - struct v4l2_pix_format_mplane *fmt) +static void v4l_print_dv_timings_cap(const void *arg, bool write_only) { - int i; + const struct v4l2_dv_timings_cap *p = arg; - dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " - "colorspace=%d, num_planes=%d\n", - fmt->width, fmt->height, - (fmt->pixelformat & 0xff), - (fmt->pixelformat >> 8) & 0xff, - (fmt->pixelformat >> 16) & 0xff, - (fmt->pixelformat >> 24) & 0xff, - prt_names(fmt->field, v4l2_field_names), - fmt->colorspace, fmt->num_planes); + switch (p->type) { + case V4L2_DV_BT_656_1120: + pr_cont("type=bt-656/1120, width=%u-%u, height=%u-%u, " + "pixelclock=%llu-%llu, standards=0x%x, capabilities=0x%x\n", + p->bt.min_width, p->bt.max_width, + p->bt.min_height, p->bt.max_height, + p->bt.min_pixelclock, p->bt.max_pixelclock, + p->bt.standards, p->bt.capabilities); + break; + default: + pr_cont("type=%u\n", p->type); + break; + } +} - for (i = 0; i < fmt->num_planes; ++i) - dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i, - fmt->plane_fmt[i].bytesperline, - fmt->plane_fmt[i].sizeimage); +static void v4l_print_frmsizeenum(const void *arg, bool write_only) +{ + const struct v4l2_frmsizeenum *p = arg; + + pr_cont("index=%u, pixelformat=%c%c%c%c, type=%u", + p->index, + (p->pixel_format & 0xff), + (p->pixel_format >> 8) & 0xff, + (p->pixel_format >> 16) & 0xff, + (p->pixel_format >> 24) & 0xff, + p->type); + switch (p->type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + pr_cont(" wxh=%ux%u\n", + p->discrete.width, p->discrete.height); + break; + case V4L2_FRMSIZE_TYPE_STEPWISE: + pr_cont(" min=%ux%u, max=%ux%u, step=%ux%u\n", + p->stepwise.min_width, p->stepwise.min_height, + p->stepwise.step_width, p->stepwise.step_height, + p->stepwise.max_width, p->stepwise.max_height); + break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + /* fall through */ + default: + pr_cont("\n"); + break; + } } -static inline void v4l_print_ext_ctrls(unsigned int cmd, - struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) +static void v4l_print_frmivalenum(const void *arg, bool write_only) { - __u32 i; + const struct v4l2_frmivalenum *p = arg; - if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) - return; - dbgarg(cmd, ""); - printk(KERN_CONT "class=0x%x", c->ctrl_class); - for (i = 0; i < c->count; i++) { - if (show_vals && !c->controls[i].size) - printk(KERN_CONT " id/val=0x%x/0x%x", - c->controls[i].id, c->controls[i].value); + pr_cont("index=%u, pixelformat=%c%c%c%c, wxh=%ux%u, type=%u", + p->index, + (p->pixel_format & 0xff), + (p->pixel_format >> 8) & 0xff, + (p->pixel_format >> 16) & 0xff, + (p->pixel_format >> 24) & 0xff, + p->width, p->height, p->type); + switch (p->type) { + case V4L2_FRMIVAL_TYPE_DISCRETE: + pr_cont(" fps=%d/%d\n", + p->discrete.numerator, + p->discrete.denominator); + break; + case V4L2_FRMIVAL_TYPE_STEPWISE: + pr_cont(" min=%d/%d, max=%d/%d, step=%d/%d\n", + p->stepwise.min.numerator, + p->stepwise.min.denominator, + p->stepwise.max.numerator, + p->stepwise.max.denominator, + p->stepwise.step.numerator, + p->stepwise.step.denominator); + break; + case V4L2_FRMIVAL_TYPE_CONTINUOUS: + /* fall through */ + default: + pr_cont("\n"); + break; + } +} + +static void v4l_print_event(const void *arg, bool write_only) +{ + const struct v4l2_event *p = arg; + const struct v4l2_event_ctrl *c; + + pr_cont("type=0x%x, pending=%u, sequence=%u, id=%u, " + "timestamp=%lu.%9.9lu\n", + p->type, p->pending, p->sequence, p->id, + p->timestamp.tv_sec, p->timestamp.tv_nsec); + switch (p->type) { + case V4L2_EVENT_VSYNC: + printk(KERN_DEBUG "field=%s\n", + prt_names(p->u.vsync.field, v4l2_field_names)); + break; + case V4L2_EVENT_CTRL: + c = &p->u.ctrl; + printk(KERN_DEBUG "changes=0x%x, type=%u, ", + c->changes, c->type); + if (c->type == V4L2_CTRL_TYPE_INTEGER64) + pr_cont("value64=%lld, ", c->value64); else - printk(KERN_CONT " id=0x%x,size=%u", - c->controls[i].id, c->controls[i].size); + pr_cont("value=%d, ", c->value); + pr_cont("flags=0x%x, minimum=%d, maximum=%d, step=%d," + " default_value=%d\n", + c->flags, c->minimum, c->maximum, + c->step, c->default_value); + break; + case V4L2_EVENT_FRAME_SYNC: + pr_cont("frame_sequence=%u\n", + p->u.frame_sync.frame_sequence); + break; } - printk(KERN_CONT "\n"); -}; +} + +static void v4l_print_event_subscription(const void *arg, bool write_only) +{ + const struct v4l2_event_subscription *p = arg; -static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) + pr_cont("type=0x%x, id=0x%x, flags=0x%x\n", + p->type, p->id, p->flags); +} + +static void v4l_print_sliced_vbi_cap(const void *arg, bool write_only) +{ + const struct v4l2_sliced_vbi_cap *p = arg; + int i; + + pr_cont("type=%s, service_set=0x%08x\n", + prt_names(p->type, v4l2_type_names), p->service_set); + for (i = 0; i < 24; i++) + printk(KERN_DEBUG "line[%02u]=0x%04x, 0x%04x\n", i, + p->service_lines[0][i], + p->service_lines[1][i]); +} + +static void v4l_print_freq_band(const void *arg, bool write_only) +{ + const struct v4l2_frequency_band *p = arg; + + pr_cont("tuner=%u, type=%u, index=%u, capability=0x%x, " + "rangelow=%u, rangehigh=%u, modulation=0x%x\n", + p->tuner, p->type, p->index, + p->capability, p->rangelow, + p->rangehigh, p->modulation); +} + +static void v4l_print_u32(const void *arg, bool write_only) +{ + pr_cont("value=%u\n", *(const u32 *)arg); +} + +static void v4l_print_newline(const void *arg, bool write_only) +{ + pr_cont("\n"); +} + +static void v4l_print_default(const void *arg, bool write_only) +{ + pr_cont("driver-specific ioctl\n"); +} + +static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) { __u32 i; @@ -536,1615 +933,1234 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) return -EINVAL; } -static long __video_do_ioctl(struct file *file, - unsigned int cmd, void *arg) +static int v4l_querycap(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) { - struct video_device *vfd = video_devdata(file); - const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; - void *fh = file->private_data; - struct v4l2_fh *vfh = NULL; - int use_fh_prio = 0; - long ret = -ENOTTY; - - if (ops == NULL) { - printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n", - vfd->name); - return ret; - } + struct v4l2_capability *cap = (struct v4l2_capability *)arg; - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - vfh = file->private_data; - use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); - } + cap->version = LINUX_VERSION_CODE; + return ops->vidioc_querycap(file, fh, cap); +} - if (v4l2_is_known_ioctl(cmd)) { - struct v4l2_ioctl_info *info = &v4l2_ioctls[_IOC_NR(cmd)]; +static int v4l_s_input(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return ops->vidioc_s_input(file, fh, *(unsigned int *)arg); +} - if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) && - !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler)) - return -ENOTTY; +static int v4l_s_output(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return ops->vidioc_s_output(file, fh, *(unsigned int *)arg); +} - if (use_fh_prio && (info->flags & INFO_FL_PRIO)) { - ret = v4l2_prio_check(vfd->prio, vfh->prio); - if (ret) - return ret; - } - } +static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd; + u32 *p = arg; - if ((vfd->debug & V4L2_DEBUG_IOCTL) && - !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { - v4l_print_ioctl(vfd->name, cmd); - printk(KERN_CONT "\n"); - } + if (ops->vidioc_g_priority) + return ops->vidioc_g_priority(file, fh, arg); + vfd = video_devdata(file); + *p = v4l2_prio_max(&vfd->v4l2_dev->prio); + return 0; +} - switch (cmd) { +static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd; + struct v4l2_fh *vfh; + u32 *p = arg; + + if (ops->vidioc_s_priority) + return ops->vidioc_s_priority(file, fh, *p); + vfd = video_devdata(file); + vfh = file->private_data; + return v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p); +} - /* --- capabilities ------------------------------------------ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = (struct v4l2_capability *)arg; - - cap->version = LINUX_VERSION_CODE; - ret = ops->vidioc_querycap(file, fh, cap); - if (!ret) - dbgarg(cmd, "driver=%s, card=%s, bus=%s, " - "version=0x%08x, " - "capabilities=0x%08x, " - "device_caps=0x%08x\n", - cap->driver, cap->card, cap->bus_info, - cap->version, - cap->capabilities, - cap->device_caps); - break; - } +static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_input *p = arg; - /* --- priority ------------------------------------------ */ - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; + /* + * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & + * CAP_STD here based on ioctl handler provided by the + * driver. If the driver doesn't support these + * for a specific input, it must override these flags. + */ + if (ops->vidioc_s_std) + p->capabilities |= V4L2_IN_CAP_STD; + if (ops->vidioc_s_dv_preset) + p->capabilities |= V4L2_IN_CAP_PRESETS; + if (ops->vidioc_s_dv_timings) + p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS; + + return ops->vidioc_enum_input(file, fh, p); +} - if (ops->vidioc_g_priority) { - ret = ops->vidioc_g_priority(file, fh, p); - } else if (use_fh_prio) { - *p = v4l2_prio_max(&vfd->v4l2_dev->prio); - ret = 0; - } - if (!ret) - dbgarg(cmd, "priority is %d\n", *p); - break; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *p = arg; +static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_output *p = arg; - dbgarg(cmd, "setting priority to %d\n", *p); - if (ops->vidioc_s_priority) - ret = ops->vidioc_s_priority(file, fh, *p); - else - ret = v4l2_prio_change(&vfd->v4l2_dev->prio, - &vfh->prio, *p); - break; - } + /* + * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & + * CAP_STD here based on ioctl handler provided by the + * driver. If the driver doesn't support these + * for a specific output, it must override these flags. + */ + if (ops->vidioc_s_std) + p->capabilities |= V4L2_OUT_CAP_STD; + if (ops->vidioc_s_dv_preset) + p->capabilities |= V4L2_OUT_CAP_PRESETS; + if (ops->vidioc_s_dv_timings) + p->capabilities |= V4L2_OUT_CAP_CUSTOM_TIMINGS; + + return ops->vidioc_enum_output(file, fh, p); +} - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; +static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_fmtdesc *p = arg; - ret = -EINVAL; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (likely(ops->vidioc_enum_fmt_vid_cap)) - ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (likely(ops->vidioc_enum_fmt_vid_cap_mplane)) - ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, - fh, f); + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (unlikely(!ops->vidioc_enum_fmt_vid_cap)) break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (likely(ops->vidioc_enum_fmt_vid_overlay)) - ret = ops->vidioc_enum_fmt_vid_overlay(file, - fh, f); + return ops->vidioc_enum_fmt_vid_cap(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (likely(ops->vidioc_enum_fmt_vid_out)) - ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); + return ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (unlikely(!ops->vidioc_enum_fmt_vid_overlay)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (likely(ops->vidioc_enum_fmt_vid_out_mplane)) - ret = ops->vidioc_enum_fmt_vid_out_mplane(file, - fh, f); + return ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (unlikely(!ops->vidioc_enum_fmt_vid_out)) break; - case V4L2_BUF_TYPE_PRIVATE: - if (likely(ops->vidioc_enum_fmt_type_private)) - ret = ops->vidioc_enum_fmt_type_private(file, - fh, f); + return ops->vidioc_enum_fmt_vid_out(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane)) break; - default: + return ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); + case V4L2_BUF_TYPE_PRIVATE: + if (unlikely(!ops->vidioc_enum_fmt_type_private)) break; - } - if (likely(!ret)) - dbgarg(cmd, "index=%d, type=%d, flags=%d, " - "pixelformat=%c%c%c%c, description='%s'\n", - f->index, f->type, f->flags, - (f->pixelformat & 0xff), - (f->pixelformat >> 8) & 0xff, - (f->pixelformat >> 16) & 0xff, - (f->pixelformat >> 24) & 0xff, - f->description); - break; + return ops->vidioc_enum_fmt_type_private(file, fh, arg); } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - /* FIXME: Should be one dump per type */ - dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); - - ret = -EINVAL; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_g_fmt_vid_cap) - ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); + return -EINVAL; +} + +static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_format *p = arg; + + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (unlikely(!ops->vidioc_g_fmt_vid_cap)) break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (ops->vidioc_g_fmt_vid_cap_mplane) - ret = ops->vidioc_g_fmt_vid_cap_mplane(file, - fh, f); - if (!ret) - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + return ops->vidioc_g_fmt_vid_cap(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (unlikely(!ops->vidioc_g_fmt_vid_cap_mplane)) break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (likely(ops->vidioc_g_fmt_vid_overlay)) - ret = ops->vidioc_g_fmt_vid_overlay(file, - fh, f); + return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (unlikely(!ops->vidioc_g_fmt_vid_overlay)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_g_fmt_vid_out) - ret = ops->vidioc_g_fmt_vid_out(file, fh, f); - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); + return ops->vidioc_g_fmt_vid_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (unlikely(!ops->vidioc_g_fmt_vid_out)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (ops->vidioc_g_fmt_vid_out_mplane) - ret = ops->vidioc_g_fmt_vid_out_mplane(file, - fh, f); - if (!ret) - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + return ops->vidioc_g_fmt_vid_out(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (unlikely(!ops->vidioc_g_fmt_vid_out_mplane)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (likely(ops->vidioc_g_fmt_vid_out_overlay)) - ret = ops->vidioc_g_fmt_vid_out_overlay(file, - fh, f); + return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (unlikely(!ops->vidioc_g_fmt_vid_out_overlay)) break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (likely(ops->vidioc_g_fmt_vbi_cap)) - ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f); + return ops->vidioc_g_fmt_vid_out_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (unlikely(!ops->vidioc_g_fmt_vbi_cap)) break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - if (likely(ops->vidioc_g_fmt_vbi_out)) - ret = ops->vidioc_g_fmt_vbi_out(file, fh, f); + return ops->vidioc_g_fmt_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (unlikely(!ops->vidioc_g_fmt_vbi_out)) break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (likely(ops->vidioc_g_fmt_sliced_vbi_cap)) - ret = ops->vidioc_g_fmt_sliced_vbi_cap(file, - fh, f); + return ops->vidioc_g_fmt_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (unlikely(!ops->vidioc_g_fmt_sliced_vbi_cap)) break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (likely(ops->vidioc_g_fmt_sliced_vbi_out)) - ret = ops->vidioc_g_fmt_sliced_vbi_out(file, - fh, f); + return ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (unlikely(!ops->vidioc_g_fmt_sliced_vbi_out)) break; - case V4L2_BUF_TYPE_PRIVATE: - if (likely(ops->vidioc_g_fmt_type_private)) - ret = ops->vidioc_g_fmt_type_private(file, - fh, f); + return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_PRIVATE: + if (unlikely(!ops->vidioc_g_fmt_type_private)) break; - } - break; + return ops->vidioc_g_fmt_type_private(file, fh, arg); } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - ret = -EINVAL; + return -EINVAL; +} - /* FIXME: Should be one dump per type */ - dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names)); +static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_format *p = arg; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.pix); - v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (ops->vidioc_s_fmt_vid_cap) - ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (unlikely(!ops->vidioc_s_fmt_vid_cap)) break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - CLEAR_AFTER_FIELD(f, fmt.pix_mp); - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - if (ops->vidioc_s_fmt_vid_cap_mplane) - ret = ops->vidioc_s_fmt_vid_cap_mplane(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.pix); + return ops->vidioc_s_fmt_vid_cap(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane)) break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_s_fmt_vid_overlay) - ret = ops->vidioc_s_fmt_vid_overlay(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.pix_mp); + return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (unlikely(!ops->vidioc_s_fmt_vid_overlay)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.pix); - v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (ops->vidioc_s_fmt_vid_out) - ret = ops->vidioc_s_fmt_vid_out(file, fh, f); + CLEAR_AFTER_FIELD(p, fmt.win); + return ops->vidioc_s_fmt_vid_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (unlikely(!ops->vidioc_s_fmt_vid_out)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - CLEAR_AFTER_FIELD(f, fmt.pix_mp); - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); - if (ops->vidioc_s_fmt_vid_out_mplane) - ret = ops->vidioc_s_fmt_vid_out_mplane(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.pix); + return ops->vidioc_s_fmt_vid_out(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_s_fmt_vid_out_overlay) - ret = ops->vidioc_s_fmt_vid_out_overlay(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.pix_mp); + return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay)) break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.vbi); - if (likely(ops->vidioc_s_fmt_vbi_cap)) - ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f); + CLEAR_AFTER_FIELD(p, fmt.win); + return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (unlikely(!ops->vidioc_s_fmt_vbi_cap)) break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.vbi); - if (likely(ops->vidioc_s_fmt_vbi_out)) - ret = ops->vidioc_s_fmt_vbi_out(file, fh, f); + CLEAR_AFTER_FIELD(p, fmt.vbi); + return ops->vidioc_s_fmt_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (unlikely(!ops->vidioc_s_fmt_vbi_out)) break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.sliced); - if (likely(ops->vidioc_s_fmt_sliced_vbi_cap)) - ret = ops->vidioc_s_fmt_sliced_vbi_cap(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.vbi); + return ops->vidioc_s_fmt_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap)) break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.sliced); - if (likely(ops->vidioc_s_fmt_sliced_vbi_out)) - ret = ops->vidioc_s_fmt_sliced_vbi_out(file, - fh, f); - + CLEAR_AFTER_FIELD(p, fmt.sliced); + return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out)) break; - case V4L2_BUF_TYPE_PRIVATE: - /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ - if (likely(ops->vidioc_s_fmt_type_private)) - ret = ops->vidioc_s_fmt_type_private(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.sliced); + return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_PRIVATE: + if (unlikely(!ops->vidioc_s_fmt_type_private)) break; - } - break; + return ops->vidioc_s_fmt_type_private(file, fh, arg); } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = (struct v4l2_format *)arg; - - /* FIXME: Should be one dump per type */ - dbgarg(cmd, "type=%s\n", prt_names(f->type, - v4l2_type_names)); - ret = -EINVAL; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.pix); - if (ops->vidioc_try_fmt_vid_cap) - ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); + return -EINVAL; +} + +static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_format *p = arg; + + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (unlikely(!ops->vidioc_try_fmt_vid_cap)) break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - CLEAR_AFTER_FIELD(f, fmt.pix_mp); - if (ops->vidioc_try_fmt_vid_cap_mplane) - ret = ops->vidioc_try_fmt_vid_cap_mplane(file, - fh, f); - if (!ret) - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + CLEAR_AFTER_FIELD(p, fmt.pix); + return ops->vidioc_try_fmt_vid_cap(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane)) break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - CLEAR_AFTER_FIELD(f, fmt.win); - if (likely(ops->vidioc_try_fmt_vid_overlay)) - ret = ops->vidioc_try_fmt_vid_overlay(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.pix_mp); + return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (unlikely(!ops->vidioc_try_fmt_vid_overlay)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.pix); - if (ops->vidioc_try_fmt_vid_out) - ret = ops->vidioc_try_fmt_vid_out(file, fh, f); - if (!ret) - v4l_print_pix_fmt(vfd, &f->fmt.pix); + CLEAR_AFTER_FIELD(p, fmt.win); + return ops->vidioc_try_fmt_vid_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (unlikely(!ops->vidioc_try_fmt_vid_out)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - CLEAR_AFTER_FIELD(f, fmt.pix_mp); - if (ops->vidioc_try_fmt_vid_out_mplane) - ret = ops->vidioc_try_fmt_vid_out_mplane(file, - fh, f); - if (!ret) - v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + CLEAR_AFTER_FIELD(p, fmt.pix); + return ops->vidioc_try_fmt_vid_out(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane)) break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - CLEAR_AFTER_FIELD(f, fmt.win); - if (likely(ops->vidioc_try_fmt_vid_out_overlay)) - ret = ops->vidioc_try_fmt_vid_out_overlay(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.pix_mp); + return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay)) break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.vbi); - if (likely(ops->vidioc_try_fmt_vbi_cap)) - ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f); + CLEAR_AFTER_FIELD(p, fmt.win); + return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (unlikely(!ops->vidioc_try_fmt_vbi_cap)) break; - case V4L2_BUF_TYPE_VBI_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.vbi); - if (likely(ops->vidioc_try_fmt_vbi_out)) - ret = ops->vidioc_try_fmt_vbi_out(file, fh, f); + CLEAR_AFTER_FIELD(p, fmt.vbi); + return ops->vidioc_try_fmt_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_VBI_OUTPUT: + if (unlikely(!ops->vidioc_try_fmt_vbi_out)) break; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - CLEAR_AFTER_FIELD(f, fmt.sliced); - if (likely(ops->vidioc_try_fmt_sliced_vbi_cap)) - ret = ops->vidioc_try_fmt_sliced_vbi_cap(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.vbi); + return ops->vidioc_try_fmt_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap)) break; - case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - CLEAR_AFTER_FIELD(f, fmt.sliced); - if (likely(ops->vidioc_try_fmt_sliced_vbi_out)) - ret = ops->vidioc_try_fmt_sliced_vbi_out(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.sliced); + return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg); + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out)) break; - case V4L2_BUF_TYPE_PRIVATE: - /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ - if (likely(ops->vidioc_try_fmt_type_private)) - ret = ops->vidioc_try_fmt_type_private(file, - fh, f); + CLEAR_AFTER_FIELD(p, fmt.sliced); + return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); + case V4L2_BUF_TYPE_PRIVATE: + if (unlikely(!ops->vidioc_try_fmt_type_private)) break; - } - break; + return ops->vidioc_try_fmt_type_private(file, fh, arg); } - /* FIXME: Those buf reqs could be handled here, - with some changes on videobuf to allow its header to be included at - videodev2.h or being merged at videodev2. - */ - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *p = arg; + return -EINVAL; +} - ret = check_fmt(ops, p->type); - if (ret) - break; +static int v4l_streamon(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return ops->vidioc_streamon(file, fh, *(unsigned int *)arg); +} - if (p->type < V4L2_BUF_TYPE_PRIVATE) - CLEAR_AFTER_FIELD(p, memory); +static int v4l_streamoff(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return ops->vidioc_streamoff(file, fh, *(unsigned int *)arg); +} - ret = ops->vidioc_reqbufs(file, fh, p); - dbgarg(cmd, "count=%d, type=%s, memory=%s\n", - p->count, - prt_names(p->type, v4l2_type_names), - prt_names(p->memory, v4l2_memory_names)); - break; - } - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *p = arg; +static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_tuner *p = arg; + int err; - ret = check_fmt(ops, p->type); - if (ret) - break; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + err = ops->vidioc_g_tuner(file, fh, p); + if (!err) + p->capability |= V4L2_TUNER_CAP_FREQ_BANDS; + return err; +} - ret = ops->vidioc_querybuf(file, fh, p); - if (!ret) - dbgbuf(cmd, vfd, p); - break; - } - case VIDIOC_QBUF: - { - struct v4l2_buffer *p = arg; +static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_tuner *p = arg; - ret = check_fmt(ops, p->type); - if (ret) - break; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + return ops->vidioc_s_tuner(file, fh, p); +} - ret = ops->vidioc_qbuf(file, fh, p); - if (!ret) - dbgbuf(cmd, vfd, p); - break; - } - case VIDIOC_DQBUF: - { - struct v4l2_buffer *p = arg; +static int v4l_g_modulator(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_modulator *p = arg; + int err; - ret = check_fmt(ops, p->type); - if (ret) - break; + err = ops->vidioc_g_modulator(file, fh, p); + if (!err) + p->capability |= V4L2_TUNER_CAP_FREQ_BANDS; + return err; +} - ret = ops->vidioc_dqbuf(file, fh, p); - if (!ret) - dbgbuf(cmd, vfd, p); - break; - } - case VIDIOC_OVERLAY: - { - int *i = arg; +static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_frequency *p = arg; - dbgarg(cmd, "value=%d\n", *i); - ret = ops->vidioc_overlay(file, fh, *i); - break; - } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *p = arg; - - ret = ops->vidioc_g_fbuf(file, fh, arg); - if (!ret) { - dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", - p->capability, p->flags, - (unsigned long)p->base); - v4l_print_pix_fmt(vfd, &p->fmt); - } - break; - } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *p = arg; - - dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", - p->capability, p->flags, (unsigned long)p->base); - v4l_print_pix_fmt(vfd, &p->fmt); - ret = ops->vidioc_s_fbuf(file, fh, arg); - break; - } - case VIDIOC_STREAMON: - { - enum v4l2_buf_type i = *(int *)arg; + p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + return ops->vidioc_g_frequency(file, fh, p); +} - dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret = ops->vidioc_streamon(file, fh, i); - break; - } - case VIDIOC_STREAMOFF: - { - enum v4l2_buf_type i = *(int *)arg; +static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_frequency *p = arg; + enum v4l2_tuner_type type; - dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret = ops->vidioc_streamoff(file, fh, i); - break; - } - /* ---------- tv norms ---------- */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *p = arg; - v4l2_std_id id = vfd->tvnorms, curr_id = 0; - unsigned int index = p->index, i, j = 0; - const char *descr = ""; - - if (id == 0) - break; - ret = -EINVAL; - - /* Return norm array in a canonical way */ - for (i = 0; i <= index && id; i++) { - /* last std value in the standards array is 0, so this - while always ends there since (id & 0) == 0. */ - while ((id & standards[j].std) != standards[j].std) - j++; - curr_id = standards[j].std; - descr = standards[j].descr; + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + if (p->type != type) + return -EINVAL; + return ops->vidioc_s_frequency(file, fh, p); +} + +static int v4l_enumstd(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_standard *p = arg; + v4l2_std_id id = vfd->tvnorms, curr_id = 0; + unsigned int index = p->index, i, j = 0; + const char *descr = ""; + + /* Return norm array in a canonical way */ + for (i = 0; i <= index && id; i++) { + /* last std value in the standards array is 0, so this + while always ends there since (id & 0) == 0. */ + while ((id & standards[j].std) != standards[j].std) j++; - if (curr_id == 0) - break; - if (curr_id != V4L2_STD_PAL && - curr_id != V4L2_STD_SECAM && - curr_id != V4L2_STD_NTSC) - id &= ~curr_id; - } - if (i <= index) + curr_id = standards[j].std; + descr = standards[j].descr; + j++; + if (curr_id == 0) break; + if (curr_id != V4L2_STD_PAL && + curr_id != V4L2_STD_SECAM && + curr_id != V4L2_STD_NTSC) + id &= ~curr_id; + } + if (i <= index) + return -EINVAL; - v4l2_video_std_construct(p, curr_id, descr); + v4l2_video_std_construct(p, curr_id, descr); + return 0; +} - dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, " - "framelines=%d\n", p->index, - (unsigned long long)p->id, p->name, - p->frameperiod.numerator, - p->frameperiod.denominator, - p->framelines); +static int v4l_g_std(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + v4l2_std_id *id = arg; - ret = 0; - break; + /* Calls the specific handler */ + if (ops->vidioc_g_std) + return ops->vidioc_g_std(file, fh, arg); + if (vfd->current_norm) { + *id = vfd->current_norm; + return 0; } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - - /* Calls the specific handler */ - if (ops->vidioc_g_std) - ret = ops->vidioc_g_std(file, fh, id); - else if (vfd->current_norm) { - ret = 0; - *id = vfd->current_norm; - } + return -ENOTTY; +} - if (likely(!ret)) - dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg, norm; +static int v4l_s_std(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + v4l2_std_id *id = arg, norm; + int ret; - dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id); + norm = (*id) & vfd->tvnorms; + if (vfd->tvnorms && !norm) /* Check if std is supported */ + return -EINVAL; - ret = -EINVAL; - norm = (*id) & vfd->tvnorms; - if (vfd->tvnorms && !norm) /* Check if std is supported */ - break; + /* Calls the specific handler */ + ret = ops->vidioc_s_std(file, fh, &norm); - /* Calls the specific handler */ - ret = ops->vidioc_s_std(file, fh, &norm); + /* Updates standard information */ + if (ret >= 0) + vfd->current_norm = norm; + return ret; +} - /* Updates standard information */ - if (ret >= 0) - vfd->current_norm = norm; - break; - } - case VIDIOC_QUERYSTD: - { - v4l2_std_id *p = arg; +static int v4l_querystd(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + v4l2_std_id *p = arg; + + /* + * If nothing detected, it should return all supported + * standard. + * Drivers just need to mask the std argument, in order + * to remove the standards that don't apply from the mask. + * This means that tuners, audio and video decoders can join + * their efforts to improve the standards detection. + */ + *p = vfd->tvnorms; + return ops->vidioc_querystd(file, fh, arg); +} - /* - * If nothing detected, it should return all supported - * Drivers just need to mask the std argument, in order - * to remove the standards that don't apply from the mask. - * This means that tuners, audio and video decoders can join - * their efforts to improve the standards detection - */ - *p = vfd->tvnorms; - ret = ops->vidioc_querystd(file, fh, arg); - if (!ret) - dbgarg(cmd, "detected std=%08Lx\n", - (unsigned long long)*p); - break; - } - /* ------ input switching ---------- */ - /* FIXME: Inputs can be handled inside videodev2 */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *p = arg; +static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_hw_freq_seek *p = arg; + enum v4l2_tuner_type type; - /* - * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & - * CAP_STD here based on ioctl handler provided by the - * driver. If the driver doesn't support these - * for a specific input, it must override these flags. - */ - if (ops->vidioc_s_std) - p->capabilities |= V4L2_IN_CAP_STD; - if (ops->vidioc_s_dv_preset) - p->capabilities |= V4L2_IN_CAP_PRESETS; - if (ops->vidioc_s_dv_timings) - p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS; - - ret = ops->vidioc_enum_input(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "audioset=%d, " - "tuner=%d, std=%08Lx, status=%d\n", - p->index, p->name, p->type, p->audioset, - p->tuner, - (unsigned long long)p->std, - p->status); - break; - } - case VIDIOC_G_INPUT: - { - unsigned int *i = arg; + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + if (p->type != type) + return -EINVAL; + return ops->vidioc_s_hw_freq_seek(file, fh, p); +} - ret = ops->vidioc_g_input(file, fh, i); - if (!ret) - dbgarg(cmd, "value=%d\n", *i); - break; - } - case VIDIOC_S_INPUT: - { - unsigned int *i = arg; +static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_requestbuffers *p = arg; + int ret = check_fmt(ops, p->type); - dbgarg(cmd, "value=%d\n", *i); - ret = ops->vidioc_s_input(file, fh, *i); - break; - } + if (ret) + return ret; - /* ------ output switching ---------- */ - case VIDIOC_ENUMOUTPUT: - { - struct v4l2_output *p = arg; + if (p->type < V4L2_BUF_TYPE_PRIVATE) + CLEAR_AFTER_FIELD(p, memory); - /* - * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & - * CAP_STD here based on ioctl handler provided by the - * driver. If the driver doesn't support these - * for a specific output, it must override these flags. - */ - if (ops->vidioc_s_std) - p->capabilities |= V4L2_OUT_CAP_STD; - if (ops->vidioc_s_dv_preset) - p->capabilities |= V4L2_OUT_CAP_PRESETS; - if (ops->vidioc_s_dv_timings) - p->capabilities |= V4L2_OUT_CAP_CUSTOM_TIMINGS; - - ret = ops->vidioc_enum_output(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "audioset=0x%x, " - "modulator=%d, std=0x%08Lx\n", - p->index, p->name, p->type, p->audioset, - p->modulator, (unsigned long long)p->std); - break; - } - case VIDIOC_G_OUTPUT: - { - unsigned int *i = arg; + return ops->vidioc_reqbufs(file, fh, p); +} - ret = ops->vidioc_g_output(file, fh, i); - if (!ret) - dbgarg(cmd, "value=%d\n", *i); - break; - } - case VIDIOC_S_OUTPUT: - { - unsigned int *i = arg; +static int v4l_querybuf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_buffer *p = arg; + int ret = check_fmt(ops, p->type); - dbgarg(cmd, "value=%d\n", *i); - ret = ops->vidioc_s_output(file, fh, *i); - break; - } + return ret ? ret : ops->vidioc_querybuf(file, fh, p); +} - /* --- controls ---------------------------------------------- */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *p = arg; - - if (vfh && vfh->ctrl_handler) - ret = v4l2_queryctrl(vfh->ctrl_handler, p); - else if (vfd->ctrl_handler) - ret = v4l2_queryctrl(vfd->ctrl_handler, p); - else if (ops->vidioc_queryctrl) - ret = ops->vidioc_queryctrl(file, fh, p); - else - break; - if (!ret) - dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " - "step=%d, default=%d, flags=0x%08x\n", - p->id, p->type, p->name, - p->minimum, p->maximum, - p->step, p->default_value, p->flags); - else - dbgarg(cmd, "id=0x%x\n", p->id); - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *p = arg; - - if (vfh && vfh->ctrl_handler) - ret = v4l2_g_ctrl(vfh->ctrl_handler, p); - else if (vfd->ctrl_handler) - ret = v4l2_g_ctrl(vfd->ctrl_handler, p); - else if (ops->vidioc_g_ctrl) - ret = ops->vidioc_g_ctrl(file, fh, p); - else if (ops->vidioc_g_ext_ctrls) { - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control ctrl; - - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); - ctrls.count = 1; - ctrls.controls = &ctrl; - ctrl.id = p->id; - ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) { - ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); - if (ret == 0) - p->value = ctrl.value; - } - } else - break; - if (!ret) - dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); - else - dbgarg(cmd, "id=0x%x\n", p->id); - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *p = arg; - struct v4l2_ext_controls ctrls; - struct v4l2_ext_control ctrl; - - if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler && - !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls) - break; +static int v4l_qbuf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_buffer *p = arg; + int ret = check_fmt(ops, p->type); - dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); + return ret ? ret : ops->vidioc_qbuf(file, fh, p); +} - if (vfh && vfh->ctrl_handler) { - ret = v4l2_s_ctrl(vfh, vfh->ctrl_handler, p); - break; - } - if (vfd->ctrl_handler) { - ret = v4l2_s_ctrl(NULL, vfd->ctrl_handler, p); - break; - } - if (ops->vidioc_s_ctrl) { - ret = ops->vidioc_s_ctrl(file, fh, p); - break; - } - if (!ops->vidioc_s_ext_ctrls) - break; +static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_buffer *p = arg; + int ret = check_fmt(ops, p->type); - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); - ctrls.count = 1; - ctrls.controls = &ctrl; - ctrl.id = p->id; - ctrl.value = p->value; - if (check_ext_ctrls(&ctrls, 1)) - ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); - else - ret = -EINVAL; - break; - } - case VIDIOC_G_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; - - p->error_idx = p->count; - if (vfh && vfh->ctrl_handler) - ret = v4l2_g_ext_ctrls(vfh->ctrl_handler, p); - else if (vfd->ctrl_handler) - ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p); - else if (ops->vidioc_g_ext_ctrls) - ret = check_ext_ctrls(p, 0) ? - ops->vidioc_g_ext_ctrls(file, fh, p) : - -EINVAL; - else - break; - v4l_print_ext_ctrls(cmd, vfd, p, !ret); - break; - } - case VIDIOC_S_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; + return ret ? ret : ops->vidioc_dqbuf(file, fh, p); +} - p->error_idx = p->count; - if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler && - !ops->vidioc_s_ext_ctrls) - break; - v4l_print_ext_ctrls(cmd, vfd, p, 1); - if (vfh && vfh->ctrl_handler) - ret = v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p); - else if (vfd->ctrl_handler) - ret = v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p); - else if (check_ext_ctrls(p, 0)) - ret = ops->vidioc_s_ext_ctrls(file, fh, p); - else - ret = -EINVAL; - break; - } - case VIDIOC_TRY_EXT_CTRLS: - { - struct v4l2_ext_controls *p = arg; +static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_create_buffers *create = arg; + int ret = check_fmt(ops, create->format.type); - p->error_idx = p->count; - if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler && - !ops->vidioc_try_ext_ctrls) - break; - v4l_print_ext_ctrls(cmd, vfd, p, 1); - if (vfh && vfh->ctrl_handler) - ret = v4l2_try_ext_ctrls(vfh->ctrl_handler, p); - else if (vfd->ctrl_handler) - ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p); - else if (check_ext_ctrls(p, 0)) - ret = ops->vidioc_try_ext_ctrls(file, fh, p); - else - ret = -EINVAL; - break; - } - case VIDIOC_QUERYMENU: - { - struct v4l2_querymenu *p = arg; - - if (vfh && vfh->ctrl_handler) - ret = v4l2_querymenu(vfh->ctrl_handler, p); - else if (vfd->ctrl_handler) - ret = v4l2_querymenu(vfd->ctrl_handler, p); - else if (ops->vidioc_querymenu) - ret = ops->vidioc_querymenu(file, fh, p); - else - break; - if (!ret) - dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", - p->id, p->index, p->name); - else - dbgarg(cmd, "id=0x%x, index=%d\n", - p->id, p->index); - break; - } - /* --- audio ---------------------------------------------- */ - case VIDIOC_ENUMAUDIO: - { - struct v4l2_audio *p = arg; - - ret = ops->vidioc_enumaudio(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, p->name, - p->capability, p->mode); - else - dbgarg(cmd, "index=%d\n", p->index); - break; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *p = arg; - - ret = ops->vidioc_g_audio(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, - p->name, p->capability, p->mode); - else - dbgarg(cmd, "index=%d\n", p->index); - break; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *p = arg; - - dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " - "mode=0x%x\n", p->index, p->name, - p->capability, p->mode); - ret = ops->vidioc_s_audio(file, fh, p); - break; - } - case VIDIOC_ENUMAUDOUT: - { - struct v4l2_audioout *p = arg; - - dbgarg(cmd, "Enum for index=%d\n", p->index); - ret = ops->vidioc_enumaudout(file, fh, p); - if (!ret) - dbgarg2("index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability, p->mode); - break; - } - case VIDIOC_G_AUDOUT: - { - struct v4l2_audioout *p = arg; - - ret = ops->vidioc_g_audout(file, fh, p); - if (!ret) - dbgarg2("index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability, p->mode); - break; - } - case VIDIOC_S_AUDOUT: - { - struct v4l2_audioout *p = arg; + return ret ? ret : ops->vidioc_create_bufs(file, fh, create); +} - dbgarg(cmd, "index=%d, name=%s, capability=%d, " - "mode=%d\n", p->index, p->name, - p->capability, p->mode); +static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_buffer *b = arg; + int ret = check_fmt(ops, b->type); - ret = ops->vidioc_s_audout(file, fh, p); - break; - } - case VIDIOC_G_MODULATOR: - { - struct v4l2_modulator *p = arg; - - ret = ops->vidioc_g_modulator(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, " - "capability=%d, rangelow=%d," - " rangehigh=%d, txsubchans=%d\n", - p->index, p->name, p->capability, - p->rangelow, p->rangehigh, - p->txsubchans); - break; - } - case VIDIOC_S_MODULATOR: - { - struct v4l2_modulator *p = arg; - - dbgarg(cmd, "index=%d, name=%s, capability=%d, " - "rangelow=%d, rangehigh=%d, txsubchans=%d\n", - p->index, p->name, p->capability, p->rangelow, - p->rangehigh, p->txsubchans); - ret = ops->vidioc_s_modulator(file, fh, p); - break; - } - case VIDIOC_G_CROP: - { - struct v4l2_crop *p = arg; + return ret ? ret : ops->vidioc_prepare_buf(file, fh, b); +} - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); +static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_streamparm *p = arg; + v4l2_std_id std; + int ret = check_fmt(ops, p->type); - if (ops->vidioc_g_crop) { - ret = ops->vidioc_g_crop(file, fh, p); - } else { - /* simulate capture crop using selection api */ - struct v4l2_selection s = { - .type = p->type, - }; - - /* crop means compose for output devices */ - if (V4L2_TYPE_IS_OUTPUT(p->type)) - s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; - else - s.target = V4L2_SEL_TGT_CROP_ACTIVE; - - ret = ops->vidioc_g_selection(file, fh, &s); - - /* copying results to old structure on success */ - if (!ret) - p->c = s.r; - } + if (ret) + return ret; + if (ops->vidioc_g_parm) + return ops->vidioc_g_parm(file, fh, p); + std = vfd->current_norm; + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + p->parm.capture.readbuffers = 2; + if (ops->vidioc_g_std) + ret = ops->vidioc_g_std(file, fh, &std); + if (ret == 0) + v4l2_video_std_frame_period(std, + &p->parm.capture.timeperframe); + return ret; +} - if (!ret) - dbgrect(vfd, "", &p->c); - break; - } - case VIDIOC_S_CROP: - { - struct v4l2_crop *p = arg; +static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_streamparm *p = arg; + int ret = check_fmt(ops, p->type); - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - dbgrect(vfd, "", &p->c); + return ret ? ret : ops->vidioc_s_parm(file, fh, p); +} - if (ops->vidioc_s_crop) { - ret = ops->vidioc_s_crop(file, fh, p); - } else { - /* simulate capture crop using selection api */ - struct v4l2_selection s = { - .type = p->type, - .r = p->c, - }; - - /* crop means compose for output devices */ - if (V4L2_TYPE_IS_OUTPUT(p->type)) - s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; - else - s.target = V4L2_SEL_TGT_CROP_ACTIVE; - - ret = ops->vidioc_s_selection(file, fh, &s); - } - break; - } - case VIDIOC_G_SELECTION: - { - struct v4l2_selection *p = arg; +static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_queryctrl *p = arg; + struct v4l2_fh *vfh = + test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + + if (vfh && vfh->ctrl_handler) + return v4l2_queryctrl(vfh->ctrl_handler, p); + if (vfd->ctrl_handler) + return v4l2_queryctrl(vfd->ctrl_handler, p); + if (ops->vidioc_queryctrl) + return ops->vidioc_queryctrl(file, fh, p); + return -ENOTTY; +} - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); +static int v4l_querymenu(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_querymenu *p = arg; + struct v4l2_fh *vfh = + test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + + if (vfh && vfh->ctrl_handler) + return v4l2_querymenu(vfh->ctrl_handler, p); + if (vfd->ctrl_handler) + return v4l2_querymenu(vfd->ctrl_handler, p); + if (ops->vidioc_querymenu) + return ops->vidioc_querymenu(file, fh, p); + return -ENOTTY; +} - ret = ops->vidioc_g_selection(file, fh, p); - if (!ret) - dbgrect(vfd, "", &p->r); - break; +static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_control *p = arg; + struct v4l2_fh *vfh = + test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control ctrl; + + if (vfh && vfh->ctrl_handler) + return v4l2_g_ctrl(vfh->ctrl_handler, p); + if (vfd->ctrl_handler) + return v4l2_g_ctrl(vfd->ctrl_handler, p); + if (ops->vidioc_g_ctrl) + return ops->vidioc_g_ctrl(file, fh, p); + if (ops->vidioc_g_ext_ctrls == NULL) + return -ENOTTY; + + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.count = 1; + ctrls.controls = &ctrl; + ctrl.id = p->id; + ctrl.value = p->value; + if (check_ext_ctrls(&ctrls, 1)) { + int ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); + + if (ret == 0) + p->value = ctrl.value; + return ret; } - case VIDIOC_S_SELECTION: - { - struct v4l2_selection *p = arg; + return -EINVAL; +} +static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_control *p = arg; + struct v4l2_fh *vfh = + test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control ctrl; + + if (vfh && vfh->ctrl_handler) + return v4l2_s_ctrl(vfh, vfh->ctrl_handler, p); + if (vfd->ctrl_handler) + return v4l2_s_ctrl(NULL, vfd->ctrl_handler, p); + if (ops->vidioc_s_ctrl) + return ops->vidioc_s_ctrl(file, fh, p); + if (ops->vidioc_s_ext_ctrls == NULL) + return -ENOTTY; + + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.count = 1; + ctrls.controls = &ctrl; + ctrl.id = p->id; + ctrl.value = p->value; + if (check_ext_ctrls(&ctrls, 1)) + return ops->vidioc_s_ext_ctrls(file, fh, &ctrls); + return -EINVAL; +} - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - dbgrect(vfd, "", &p->r); +static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_ext_controls *p = arg; + struct v4l2_fh *vfh = + test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + + p->error_idx = p->count; + if (vfh && vfh->ctrl_handler) + return v4l2_g_ext_ctrls(vfh->ctrl_handler, p); + if (vfd->ctrl_handler) + return v4l2_g_ext_ctrls(vfd->ctrl_handler, p); + if (ops->vidioc_g_ext_ctrls == NULL) + return -ENOTTY; + return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) : + -EINVAL; +} - ret = ops->vidioc_s_selection(file, fh, p); - break; - } - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *p = arg; - - /*FIXME: Should also show v4l2_fract pixelaspect */ - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - if (ops->vidioc_cropcap) { - ret = ops->vidioc_cropcap(file, fh, p); - } else { - struct v4l2_selection s = { .type = p->type }; +static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_ext_controls *p = arg; + struct v4l2_fh *vfh = + test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + + p->error_idx = p->count; + if (vfh && vfh->ctrl_handler) + return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p); + if (vfd->ctrl_handler) + return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p); + if (ops->vidioc_s_ext_ctrls == NULL) + return -ENOTTY; + return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) : + -EINVAL; +} - /* obtaining bounds */ - if (V4L2_TYPE_IS_OUTPUT(p->type)) - s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS; - else - s.target = V4L2_SEL_TGT_CROP_BOUNDS; +static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_ext_controls *p = arg; + struct v4l2_fh *vfh = + test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + + p->error_idx = p->count; + if (vfh && vfh->ctrl_handler) + return v4l2_try_ext_ctrls(vfh->ctrl_handler, p); + if (vfd->ctrl_handler) + return v4l2_try_ext_ctrls(vfd->ctrl_handler, p); + if (ops->vidioc_try_ext_ctrls == NULL) + return -ENOTTY; + return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) : + -EINVAL; +} - ret = ops->vidioc_g_selection(file, fh, &s); - if (ret) - break; - p->bounds = s.r; +static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_crop *p = arg; + struct v4l2_selection s = { + .type = p->type, + }; + int ret; + + if (ops->vidioc_g_crop) + return ops->vidioc_g_crop(file, fh, p); + /* simulate capture crop using selection api */ + + /* crop means compose for output devices */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + else + s.target = V4L2_SEL_TGT_CROP_ACTIVE; + + ret = ops->vidioc_g_selection(file, fh, &s); + + /* copying results to old structure on success */ + if (!ret) + p->c = s.r; + return ret; +} - /* obtaining defrect */ - if (V4L2_TYPE_IS_OUTPUT(p->type)) - s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; - else - s.target = V4L2_SEL_TGT_CROP_DEFAULT; +static int v4l_s_crop(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_crop *p = arg; + struct v4l2_selection s = { + .type = p->type, + .r = p->c, + }; + + if (ops->vidioc_s_crop) + return ops->vidioc_s_crop(file, fh, p); + /* simulate capture crop using selection api */ + + /* crop means compose for output devices */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + else + s.target = V4L2_SEL_TGT_CROP_ACTIVE; + + return ops->vidioc_s_selection(file, fh, &s); +} - ret = ops->vidioc_g_selection(file, fh, &s); - if (ret) - break; - p->defrect = s.r; +static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_cropcap *p = arg; + struct v4l2_selection s = { .type = p->type }; + int ret; - /* setting trivial pixelaspect */ - p->pixelaspect.numerator = 1; - p->pixelaspect.denominator = 1; - } + if (ops->vidioc_cropcap) + return ops->vidioc_cropcap(file, fh, p); - if (!ret) { - dbgrect(vfd, "bounds ", &p->bounds); - dbgrect(vfd, "defrect ", &p->defrect); - } - break; - } - case VIDIOC_G_JPEGCOMP: - { - struct v4l2_jpegcompression *p = arg; - - ret = ops->vidioc_g_jpegcomp(file, fh, p); - if (!ret) - dbgarg(cmd, "quality=%d, APPn=%d, " - "APP_len=%d, COM_len=%d, " - "jpeg_markers=%d\n", - p->quality, p->APPn, p->APP_len, - p->COM_len, p->jpeg_markers); - break; - } - case VIDIOC_S_JPEGCOMP: - { - struct v4l2_jpegcompression *p = arg; - - dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, " - "COM_len=%d, jpeg_markers=%d\n", - p->quality, p->APPn, p->APP_len, - p->COM_len, p->jpeg_markers); - ret = ops->vidioc_s_jpegcomp(file, fh, p); - break; - } - case VIDIOC_G_ENC_INDEX: - { - struct v4l2_enc_idx *p = arg; - - ret = ops->vidioc_g_enc_index(file, fh, p); - if (!ret) - dbgarg(cmd, "entries=%d, entries_cap=%d\n", - p->entries, p->entries_cap); - break; - } - case VIDIOC_ENCODER_CMD: - { - struct v4l2_encoder_cmd *p = arg; + /* obtaining bounds */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS; + else + s.target = V4L2_SEL_TGT_CROP_BOUNDS; - ret = ops->vidioc_encoder_cmd(file, fh, p); - if (!ret) - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } - case VIDIOC_TRY_ENCODER_CMD: - { - struct v4l2_encoder_cmd *p = arg; + ret = ops->vidioc_g_selection(file, fh, &s); + if (ret) + return ret; + p->bounds = s.r; - ret = ops->vidioc_try_encoder_cmd(file, fh, p); - if (!ret) - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } - case VIDIOC_DECODER_CMD: - { - struct v4l2_decoder_cmd *p = arg; + /* obtaining defrect */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; + else + s.target = V4L2_SEL_TGT_CROP_DEFAULT; - ret = ops->vidioc_decoder_cmd(file, fh, p); - if (!ret) - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } - case VIDIOC_TRY_DECODER_CMD: - { - struct v4l2_decoder_cmd *p = arg; + ret = ops->vidioc_g_selection(file, fh, &s); + if (ret) + return ret; + p->defrect = s.r; - ret = ops->vidioc_try_decoder_cmd(file, fh, p); - if (!ret) - dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); - break; - } - case VIDIOC_G_PARM: - { - struct v4l2_streamparm *p = arg; + /* setting trivial pixelaspect */ + p->pixelaspect.numerator = 1; + p->pixelaspect.denominator = 1; + return 0; +} - if (ops->vidioc_g_parm) { - ret = check_fmt(ops, p->type); - if (ret) - break; - ret = ops->vidioc_g_parm(file, fh, p); - } else { - v4l2_std_id std = vfd->current_norm; +static int v4l_log_status(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + int ret; + + if (vfd->v4l2_dev) + pr_info("%s: ================= START STATUS =================\n", + vfd->v4l2_dev->name); + ret = ops->vidioc_log_status(file, fh); + if (vfd->v4l2_dev) + pr_info("%s: ================== END STATUS ==================\n", + vfd->v4l2_dev->name); + return ret; +} - ret = -EINVAL; - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - break; +static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ +#ifdef CONFIG_VIDEO_ADV_DEBUG + struct v4l2_dbg_register *p = arg; - ret = 0; - p->parm.capture.readbuffers = 2; - if (ops->vidioc_g_std) - ret = ops->vidioc_g_std(file, fh, &std); - if (ret == 0) - v4l2_video_std_frame_period(std, - &p->parm.capture.timeperframe); - } + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return ops->vidioc_g_register(file, fh, p); +#else + return -ENOTTY; +#endif +} - dbgarg(cmd, "type=%d\n", p->type); - break; - } - case VIDIOC_S_PARM: - { - struct v4l2_streamparm *p = arg; +static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ +#ifdef CONFIG_VIDEO_ADV_DEBUG + struct v4l2_dbg_register *p = arg; - ret = check_fmt(ops, p->type); - if (ret) - break; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return ops->vidioc_s_register(file, fh, p); +#else + return -ENOTTY; +#endif +} - dbgarg(cmd, "type=%d\n", p->type); - ret = ops->vidioc_s_parm(file, fh, p); - break; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *p = arg; +static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_dbg_chip_ident *p = arg; - p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? - V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - ret = ops->vidioc_g_tuner(file, fh, p); - if (!ret) - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "capability=0x%x, rangelow=%d, " - "rangehigh=%d, signal=%d, afc=%d, " - "rxsubchans=0x%x, audmode=%d\n", - p->index, p->name, p->type, - p->capability, p->rangelow, - p->rangehigh, p->signal, p->afc, - p->rxsubchans, p->audmode); - break; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *p = arg; + p->ident = V4L2_IDENT_NONE; + p->revision = 0; + return ops->vidioc_g_chip_ident(file, fh, p); +} - p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? - V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - dbgarg(cmd, "index=%d, name=%s, type=%d, " - "capability=0x%x, rangelow=%d, " - "rangehigh=%d, signal=%d, afc=%d, " - "rxsubchans=0x%x, audmode=%d\n", - p->index, p->name, p->type, - p->capability, p->rangelow, - p->rangehigh, p->signal, p->afc, - p->rxsubchans, p->audmode); - ret = ops->vidioc_s_tuner(file, fh, p); - break; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *p = arg; +static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK); +} - p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? - V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - ret = ops->vidioc_g_frequency(file, fh, p); - if (!ret) - dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", - p->tuner, p->type, p->frequency); - break; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *p = arg; - enum v4l2_tuner_type type; +static int v4l_subscribe_event(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return ops->vidioc_subscribe_event(fh, arg); +} - type = (vfd->vfl_type == VFL_TYPE_RADIO) ? - V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", - p->tuner, p->type, p->frequency); - if (p->type != type) - ret = -EINVAL; - else - ret = ops->vidioc_s_frequency(file, fh, p); - break; - } - case VIDIOC_G_SLICED_VBI_CAP: - { - struct v4l2_sliced_vbi_cap *p = arg; +static int v4l_unsubscribe_event(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return ops->vidioc_unsubscribe_event(fh, arg); +} - /* Clear up to type, everything after type is zerod already */ - memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type)); +static int v4l_g_sliced_vbi_cap(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_sliced_vbi_cap *p = arg; - dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p); - if (!ret) - dbgarg2("service_set=%d\n", p->service_set); - break; - } - case VIDIOC_LOG_STATUS: - { - if (vfd->v4l2_dev) - pr_info("%s: ================= START STATUS =================\n", - vfd->v4l2_dev->name); - ret = ops->vidioc_log_status(file, fh); - if (vfd->v4l2_dev) - pr_info("%s: ================== END STATUS ==================\n", - vfd->v4l2_dev->name); - break; - } - case VIDIOC_DBG_G_REGISTER: - { -#ifdef CONFIG_VIDEO_ADV_DEBUG - struct v4l2_dbg_register *p = arg; + /* Clear up to type, everything after type is zeroed already */ + memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type)); - if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - else - ret = ops->vidioc_g_register(file, fh, p); -#endif - break; - } - case VIDIOC_DBG_S_REGISTER: - { -#ifdef CONFIG_VIDEO_ADV_DEBUG - struct v4l2_dbg_register *p = arg; + return ops->vidioc_g_sliced_vbi_cap(file, fh, p); +} - if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - else - ret = ops->vidioc_s_register(file, fh, p); -#endif - break; - } - case VIDIOC_DBG_G_CHIP_IDENT: - { - struct v4l2_dbg_chip_ident *p = arg; - - p->ident = V4L2_IDENT_NONE; - p->revision = 0; - ret = ops->vidioc_g_chip_ident(file, fh, p); - if (!ret) - dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); - break; - } - case VIDIOC_S_HW_FREQ_SEEK: - { - struct v4l2_hw_freq_seek *p = arg; - enum v4l2_tuner_type type; +static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_frequency_band *p = arg; + enum v4l2_tuner_type type; + int err; - type = (vfd->vfl_type == VFL_TYPE_RADIO) ? + type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - dbgarg(cmd, - "tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n", - p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing); - if (p->type != type) - ret = -EINVAL; - else - ret = ops->vidioc_s_hw_freq_seek(file, fh, p); - break; - } - case VIDIOC_ENUM_FRAMESIZES: - { - struct v4l2_frmsizeenum *p = arg; - ret = ops->vidioc_enum_framesizes(file, fh, p); - dbgarg(cmd, - "index=%d, pixelformat=%c%c%c%c, type=%d ", - p->index, - (p->pixel_format & 0xff), - (p->pixel_format >> 8) & 0xff, - (p->pixel_format >> 16) & 0xff, - (p->pixel_format >> 24) & 0xff, - p->type); - switch (p->type) { - case V4L2_FRMSIZE_TYPE_DISCRETE: - dbgarg3("width = %d, height=%d\n", - p->discrete.width, p->discrete.height); - break; - case V4L2_FRMSIZE_TYPE_STEPWISE: - dbgarg3("min %dx%d, max %dx%d, step %dx%d\n", - p->stepwise.min_width, p->stepwise.min_height, - p->stepwise.step_width, p->stepwise.step_height, - p->stepwise.max_width, p->stepwise.max_height); - break; - case V4L2_FRMSIZE_TYPE_CONTINUOUS: - dbgarg3("continuous\n"); - break; - default: - dbgarg3("- Unknown type!\n"); - } - - break; - } - case VIDIOC_ENUM_FRAMEINTERVALS: - { - struct v4l2_frmivalenum *p = arg; - - ret = ops->vidioc_enum_frameintervals(file, fh, p); - dbgarg(cmd, - "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ", - p->index, p->pixel_format, - p->width, p->height, p->type); - switch (p->type) { - case V4L2_FRMIVAL_TYPE_DISCRETE: - dbgarg2("fps=%d/%d\n", - p->discrete.numerator, - p->discrete.denominator); - break; - case V4L2_FRMIVAL_TYPE_STEPWISE: - dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n", - p->stepwise.min.numerator, - p->stepwise.min.denominator, - p->stepwise.max.numerator, - p->stepwise.max.denominator, - p->stepwise.step.numerator, - p->stepwise.step.denominator); - break; - case V4L2_FRMIVAL_TYPE_CONTINUOUS: - dbgarg2("continuous\n"); - break; - default: - dbgarg2("- Unknown type!\n"); - } - break; + if (type != p->type) + return -EINVAL; + if (ops->vidioc_enum_freq_bands) + return ops->vidioc_enum_freq_bands(file, fh, p); + if (ops->vidioc_g_tuner) { + struct v4l2_tuner t = { + .index = p->tuner, + .type = type, + }; + + err = ops->vidioc_g_tuner(file, fh, &t); + if (err) + return err; + p->capability = t.capability | V4L2_TUNER_CAP_FREQ_BANDS; + p->rangelow = t.rangelow; + p->rangehigh = t.rangehigh; + p->modulation = (type == V4L2_TUNER_RADIO) ? + V4L2_BAND_MODULATION_FM : V4L2_BAND_MODULATION_VSB; + return 0; } - case VIDIOC_ENUM_DV_PRESETS: - { - struct v4l2_dv_enum_preset *p = arg; - - ret = ops->vidioc_enum_dv_presets(file, fh, p); - if (!ret) - dbgarg(cmd, - "index=%d, preset=%d, name=%s, width=%d," - " height=%d ", - p->index, p->preset, p->name, p->width, - p->height); - break; + if (ops->vidioc_g_modulator) { + struct v4l2_modulator m = { + .index = p->tuner, + }; + + if (type != V4L2_TUNER_RADIO) + return -EINVAL; + err = ops->vidioc_g_modulator(file, fh, &m); + if (err) + return err; + p->capability = m.capability | V4L2_TUNER_CAP_FREQ_BANDS; + p->rangelow = m.rangelow; + p->rangehigh = m.rangehigh; + p->modulation = (type == V4L2_TUNER_RADIO) ? + V4L2_BAND_MODULATION_FM : V4L2_BAND_MODULATION_VSB; + return 0; } - case VIDIOC_S_DV_PRESET: - { - struct v4l2_dv_preset *p = arg; + return -ENOTTY; +} - dbgarg(cmd, "preset=%d\n", p->preset); - ret = ops->vidioc_s_dv_preset(file, fh, p); - break; - } - case VIDIOC_G_DV_PRESET: - { - struct v4l2_dv_preset *p = arg; +struct v4l2_ioctl_info { + unsigned int ioctl; + u32 flags; + const char * const name; + union { + u32 offset; + int (*func)(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *p); + } u; + void (*debug)(const void *arg, bool write_only); +}; - ret = ops->vidioc_g_dv_preset(file, fh, p); - if (!ret) - dbgarg(cmd, "preset=%d\n", p->preset); - break; +/* This control needs a priority check */ +#define INFO_FL_PRIO (1 << 0) +/* This control can be valid if the filehandle passes a control handler. */ +#define INFO_FL_CTRL (1 << 1) +/* This is a standard ioctl, no need for special code */ +#define INFO_FL_STD (1 << 2) +/* This is ioctl has its own function */ +#define INFO_FL_FUNC (1 << 3) +/* Queuing ioctl */ +#define INFO_FL_QUEUE (1 << 4) +/* Zero struct from after the field to the end */ +#define INFO_FL_CLEAR(v4l2_struct, field) \ + ((offsetof(struct v4l2_struct, field) + \ + sizeof(((struct v4l2_struct *)0)->field)) << 16) +#define INFO_FL_CLEAR_MASK (_IOC_SIZEMASK << 16) + +#define IOCTL_INFO_STD(_ioctl, _vidioc, _debug, _flags) \ + [_IOC_NR(_ioctl)] = { \ + .ioctl = _ioctl, \ + .flags = _flags | INFO_FL_STD, \ + .name = #_ioctl, \ + .u.offset = offsetof(struct v4l2_ioctl_ops, _vidioc), \ + .debug = _debug, \ + } + +#define IOCTL_INFO_FNC(_ioctl, _func, _debug, _flags) \ + [_IOC_NR(_ioctl)] = { \ + .ioctl = _ioctl, \ + .flags = _flags | INFO_FL_FUNC, \ + .name = #_ioctl, \ + .u.func = _func, \ + .debug = _debug, \ } - case VIDIOC_QUERY_DV_PRESET: - { - struct v4l2_dv_preset *p = arg; - ret = ops->vidioc_query_dv_preset(file, fh, p); - if (!ret) - dbgarg(cmd, "preset=%d\n", p->preset); - break; - } - case VIDIOC_S_DV_TIMINGS: - { - struct v4l2_dv_timings *p = arg; - - dbgtimings(vfd, p); - switch (p->type) { - case V4L2_DV_BT_656_1120: - ret = ops->vidioc_s_dv_timings(file, fh, p); - break; - default: - ret = -EINVAL; - break; - } - break; - } - case VIDIOC_G_DV_TIMINGS: - { - struct v4l2_dv_timings *p = arg; +static struct v4l2_ioctl_info v4l2_ioctls[] = { + IOCTL_INFO_FNC(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0), + IOCTL_INFO_FNC(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, INFO_FL_CLEAR(v4l2_fmtdesc, type)), + IOCTL_INFO_FNC(VIDIOC_G_FMT, v4l_g_fmt, v4l_print_format, INFO_FL_CLEAR(v4l2_format, type)), + IOCTL_INFO_FNC(VIDIOC_S_FMT, v4l_s_fmt, v4l_print_format, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE), + IOCTL_INFO_FNC(VIDIOC_QUERYBUF, v4l_querybuf, v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)), + IOCTL_INFO_STD(VIDIOC_G_FBUF, vidioc_g_fbuf, v4l_print_framebuffer, 0), + IOCTL_INFO_STD(VIDIOC_S_FBUF, vidioc_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_OVERLAY, vidioc_overlay, v4l_print_u32, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE), + IOCTL_INFO_FNC(VIDIOC_DQBUF, v4l_dqbuf, v4l_print_buffer, INFO_FL_QUEUE), + IOCTL_INFO_FNC(VIDIOC_STREAMON, v4l_streamon, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE), + IOCTL_INFO_FNC(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE), + IOCTL_INFO_FNC(VIDIOC_G_PARM, v4l_g_parm, v4l_print_streamparm, INFO_FL_CLEAR(v4l2_streamparm, type)), + IOCTL_INFO_FNC(VIDIOC_S_PARM, v4l_s_parm, v4l_print_streamparm, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_G_STD, v4l_g_std, v4l_print_std, 0), + IOCTL_INFO_FNC(VIDIOC_S_STD, v4l_s_std, v4l_print_std, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_ENUMSTD, v4l_enumstd, v4l_print_standard, INFO_FL_CLEAR(v4l2_standard, index)), + IOCTL_INFO_FNC(VIDIOC_ENUMINPUT, v4l_enuminput, v4l_print_enuminput, INFO_FL_CLEAR(v4l2_input, index)), + IOCTL_INFO_FNC(VIDIOC_G_CTRL, v4l_g_ctrl, v4l_print_control, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_control, id)), + IOCTL_INFO_FNC(VIDIOC_S_CTRL, v4l_s_ctrl, v4l_print_control, INFO_FL_PRIO | INFO_FL_CTRL), + IOCTL_INFO_FNC(VIDIOC_G_TUNER, v4l_g_tuner, v4l_print_tuner, INFO_FL_CLEAR(v4l2_tuner, index)), + IOCTL_INFO_FNC(VIDIOC_S_TUNER, v4l_s_tuner, v4l_print_tuner, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_AUDIO, vidioc_g_audio, v4l_print_audio, 0), + IOCTL_INFO_STD(VIDIOC_S_AUDIO, vidioc_s_audio, v4l_print_audio, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_QUERYCTRL, v4l_queryctrl, v4l_print_queryctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_queryctrl, id)), + IOCTL_INFO_FNC(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)), + IOCTL_INFO_STD(VIDIOC_G_INPUT, vidioc_g_input, v4l_print_u32, 0), + IOCTL_INFO_FNC(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_OUTPUT, vidioc_g_output, v4l_print_u32, 0), + IOCTL_INFO_FNC(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)), + IOCTL_INFO_STD(VIDIOC_G_AUDOUT, vidioc_g_audout, v4l_print_audioout, 0), + IOCTL_INFO_STD(VIDIOC_S_AUDOUT, vidioc_s_audout, v4l_print_audioout, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_G_MODULATOR, v4l_g_modulator, v4l_print_modulator, INFO_FL_CLEAR(v4l2_modulator, index)), + IOCTL_INFO_STD(VIDIOC_S_MODULATOR, vidioc_s_modulator, v4l_print_modulator, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_G_FREQUENCY, v4l_g_frequency, v4l_print_frequency, INFO_FL_CLEAR(v4l2_frequency, tuner)), + IOCTL_INFO_FNC(VIDIOC_S_FREQUENCY, v4l_s_frequency, v4l_print_frequency, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_CROPCAP, v4l_cropcap, v4l_print_cropcap, INFO_FL_CLEAR(v4l2_cropcap, type)), + IOCTL_INFO_FNC(VIDIOC_G_CROP, v4l_g_crop, v4l_print_crop, INFO_FL_CLEAR(v4l2_crop, type)), + IOCTL_INFO_FNC(VIDIOC_S_CROP, v4l_s_crop, v4l_print_crop, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_SELECTION, vidioc_g_selection, v4l_print_selection, 0), + IOCTL_INFO_STD(VIDIOC_S_SELECTION, vidioc_s_selection, v4l_print_selection, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp, v4l_print_jpegcompression, 0), + IOCTL_INFO_STD(VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp, v4l_print_jpegcompression, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_QUERYSTD, v4l_querystd, v4l_print_std, 0), + IOCTL_INFO_FNC(VIDIOC_TRY_FMT, v4l_try_fmt, v4l_print_format, 0), + IOCTL_INFO_STD(VIDIOC_ENUMAUDIO, vidioc_enumaudio, v4l_print_audio, INFO_FL_CLEAR(v4l2_audio, index)), + IOCTL_INFO_STD(VIDIOC_ENUMAUDOUT, vidioc_enumaudout, v4l_print_audioout, INFO_FL_CLEAR(v4l2_audioout, index)), + IOCTL_INFO_FNC(VIDIOC_G_PRIORITY, v4l_g_priority, v4l_print_u32, 0), + IOCTL_INFO_FNC(VIDIOC_S_PRIORITY, v4l_s_priority, v4l_print_u32, INFO_FL_PRIO), + IOCTL_INFO_FNC(VIDIOC_G_SLICED_VBI_CAP, v4l_g_sliced_vbi_cap, v4l_print_sliced_vbi_cap, INFO_FL_CLEAR(v4l2_sliced_vbi_cap, type)), + IOCTL_INFO_FNC(VIDIOC_LOG_STATUS, v4l_log_status, v4l_print_newline, 0), + IOCTL_INFO_FNC(VIDIOC_G_EXT_CTRLS, v4l_g_ext_ctrls, v4l_print_ext_controls, INFO_FL_CTRL), + IOCTL_INFO_FNC(VIDIOC_S_EXT_CTRLS, v4l_s_ext_ctrls, v4l_print_ext_controls, INFO_FL_PRIO | INFO_FL_CTRL), + IOCTL_INFO_FNC(VIDIOC_TRY_EXT_CTRLS, v4l_try_ext_ctrls, v4l_print_ext_controls, INFO_FL_CTRL), + IOCTL_INFO_STD(VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes, v4l_print_frmsizeenum, INFO_FL_CLEAR(v4l2_frmsizeenum, pixel_format)), + IOCTL_INFO_STD(VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals, v4l_print_frmivalenum, INFO_FL_CLEAR(v4l2_frmivalenum, height)), + IOCTL_INFO_STD(VIDIOC_G_ENC_INDEX, vidioc_g_enc_index, v4l_print_enc_idx, 0), + IOCTL_INFO_STD(VIDIOC_ENCODER_CMD, vidioc_encoder_cmd, v4l_print_encoder_cmd, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_encoder_cmd, flags)), + IOCTL_INFO_STD(VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd, v4l_print_encoder_cmd, INFO_FL_CLEAR(v4l2_encoder_cmd, flags)), + IOCTL_INFO_STD(VIDIOC_DECODER_CMD, vidioc_decoder_cmd, v4l_print_decoder_cmd, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd, v4l_print_decoder_cmd, 0), + IOCTL_INFO_FNC(VIDIOC_DBG_S_REGISTER, v4l_dbg_s_register, v4l_print_dbg_register, 0), + IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0), + IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0), + IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets, v4l_print_dv_enum_presets, 0), + IOCTL_INFO_STD(VIDIOC_S_DV_PRESET, vidioc_s_dv_preset, v4l_print_dv_preset, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_DV_PRESET, vidioc_g_dv_preset, v4l_print_dv_preset, 0), + IOCTL_INFO_STD(VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset, v4l_print_dv_preset, 0), + IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO), + IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0), + IOCTL_INFO_FNC(VIDIOC_DQEVENT, v4l_dqevent, v4l_print_event, 0), + IOCTL_INFO_FNC(VIDIOC_SUBSCRIBE_EVENT, v4l_subscribe_event, v4l_print_event_subscription, 0), + IOCTL_INFO_FNC(VIDIOC_UNSUBSCRIBE_EVENT, v4l_unsubscribe_event, v4l_print_event_subscription, 0), + IOCTL_INFO_FNC(VIDIOC_CREATE_BUFS, v4l_create_bufs, v4l_print_create_buffers, INFO_FL_PRIO | INFO_FL_QUEUE), + IOCTL_INFO_FNC(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE), + IOCTL_INFO_STD(VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings, v4l_print_enum_dv_timings, 0), + IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0), + IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)), + IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), +}; +#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) - ret = ops->vidioc_g_dv_timings(file, fh, p); - if (!ret) - dbgtimings(vfd, p); - break; - } - case VIDIOC_ENUM_DV_TIMINGS: - { - struct v4l2_enum_dv_timings *p = arg; +bool v4l2_is_known_ioctl(unsigned int cmd) +{ + if (_IOC_NR(cmd) >= V4L2_IOCTLS) + return false; + return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd; +} - if (!ops->vidioc_enum_dv_timings) - break; +struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, unsigned cmd) +{ + if (_IOC_NR(cmd) >= V4L2_IOCTLS) + return vdev->lock; + if (test_bit(_IOC_NR(cmd), vdev->disable_locking)) + return NULL; + if (vdev->queue && vdev->queue->lock && + (v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE)) + return vdev->queue->lock; + return vdev->lock; +} - ret = ops->vidioc_enum_dv_timings(file, fh, p); - if (!ret) { - dbgarg(cmd, "index=%d: ", p->index); - dbgtimings(vfd, &p->timings); - } - break; - } - case VIDIOC_QUERY_DV_TIMINGS: - { - struct v4l2_dv_timings *p = arg; +/* Common ioctl debug function. This function can be used by + external ioctl messages as well as internal V4L ioctl */ +void v4l_printk_ioctl(const char *prefix, unsigned int cmd) +{ + const char *dir, *type; - if (!ops->vidioc_query_dv_timings) - break; + if (prefix) + printk(KERN_DEBUG "%s: ", prefix); - ret = ops->vidioc_query_dv_timings(file, fh, p); - if (!ret) - dbgtimings(vfd, p); + switch (_IOC_TYPE(cmd)) { + case 'd': + type = "v4l2_int"; break; - } - case VIDIOC_DV_TIMINGS_CAP: - { - struct v4l2_dv_timings_cap *p = arg; - - if (!ops->vidioc_dv_timings_cap) - break; - - ret = ops->vidioc_dv_timings_cap(file, fh, p); - if (ret) - break; - switch (p->type) { - case V4L2_DV_BT_656_1120: - dbgarg(cmd, - "type=%d, width=%u-%u, height=%u-%u, " - "pixelclock=%llu-%llu, standards=%x, capabilities=%x ", - p->type, - p->bt.min_width, p->bt.max_width, - p->bt.min_height, p->bt.max_height, - p->bt.min_pixelclock, p->bt.max_pixelclock, - p->bt.standards, p->bt.capabilities); - break; - default: - dbgarg(cmd, "unknown type "); + case 'V': + if (_IOC_NR(cmd) >= V4L2_IOCTLS) { + type = "v4l2"; break; } + pr_cont("%s", v4l2_ioctls[_IOC_NR(cmd)].name); + return; + default: + type = "unknown"; break; } - case VIDIOC_DQEVENT: - { - struct v4l2_event *ev = arg; - ret = v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK); - if (ret < 0) { - dbgarg(cmd, "no pending events?"); - break; - } - dbgarg(cmd, - "pending=%d, type=0x%8.8x, sequence=%d, " - "timestamp=%lu.%9.9lu ", - ev->pending, ev->type, ev->sequence, - ev->timestamp.tv_sec, ev->timestamp.tv_nsec); - break; + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: dir = "--"; break; + case _IOC_READ: dir = "r-"; break; + case _IOC_WRITE: dir = "-w"; break; + case _IOC_READ | _IOC_WRITE: dir = "rw"; break; + default: dir = "*ERR*"; break; } - case VIDIOC_SUBSCRIBE_EVENT: - { - struct v4l2_event_subscription *sub = arg; + pr_cont("%s ioctl '%c', dir=%s, #%d (0x%08x)", + type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); +} +EXPORT_SYMBOL(v4l_printk_ioctl); - ret = ops->vidioc_subscribe_event(fh, sub); - if (ret < 0) { - dbgarg(cmd, "failed, ret=%ld", ret); - break; - } - dbgarg(cmd, "type=0x%8.8x", sub->type); - break; - } - case VIDIOC_UNSUBSCRIBE_EVENT: - { - struct v4l2_event_subscription *sub = arg; +static long __video_do_ioctl(struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *vfd = video_devdata(file); + const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; + bool write_only = false; + struct v4l2_ioctl_info default_info; + const struct v4l2_ioctl_info *info; + void *fh = file->private_data; + struct v4l2_fh *vfh = NULL; + int use_fh_prio = 0; + int debug = vfd->debug; + long ret = -ENOTTY; - ret = ops->vidioc_unsubscribe_event(fh, sub); - if (ret < 0) { - dbgarg(cmd, "failed, ret=%ld", ret); - break; - } - dbgarg(cmd, "type=0x%8.8x", sub->type); - break; + if (ops == NULL) { + pr_warn("%s: has no ioctl_ops.\n", + video_device_node_name(vfd)); + return ret; } - case VIDIOC_CREATE_BUFS: - { - struct v4l2_create_buffers *create = arg; - ret = check_fmt(ops, create->format.type); - if (ret) - break; - - ret = ops->vidioc_create_bufs(file, fh, create); - - dbgarg(cmd, "count=%d @ %d\n", create->count, create->index); - break; + if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { + vfh = file->private_data; + use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); } - case VIDIOC_PREPARE_BUF: - { - struct v4l2_buffer *b = arg; - - ret = check_fmt(ops, b->type); - if (ret) - break; - ret = ops->vidioc_prepare_buf(file, fh, b); + if (v4l2_is_known_ioctl(cmd)) { + info = &v4l2_ioctls[_IOC_NR(cmd)]; - dbgarg(cmd, "index=%d", b->index); - break; - } - default: - if (!ops->vidioc_default) - break; - ret = ops->vidioc_default(file, fh, use_fh_prio ? - v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0, - cmd, arg); - break; - } /* switch */ + if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) && + !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler)) + goto done; - if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { - if (ret < 0) { - v4l_print_ioctl(vfd->name, cmd); - printk(KERN_CONT " error %ld\n", ret); + if (use_fh_prio && (info->flags & INFO_FL_PRIO)) { + ret = v4l2_prio_check(vfd->prio, vfh->prio); + if (ret) + goto done; + } + } else { + default_info.ioctl = cmd; + default_info.flags = 0; + default_info.debug = v4l_print_default; + info = &default_info; + } + + write_only = _IOC_DIR(cmd) == _IOC_WRITE; + if (write_only && debug > V4L2_DEBUG_IOCTL) { + v4l_printk_ioctl(video_device_node_name(vfd), cmd); + pr_cont(": "); + info->debug(arg, write_only); + } + if (info->flags & INFO_FL_STD) { + typedef int (*vidioc_op)(struct file *file, void *fh, void *p); + const void *p = vfd->ioctl_ops; + const vidioc_op *vidioc = p + info->u.offset; + + ret = (*vidioc)(file, fh, arg); + } else if (info->flags & INFO_FL_FUNC) { + ret = info->u.func(ops, file, fh, arg); + } else if (!ops->vidioc_default) { + ret = -ENOTTY; + } else { + ret = ops->vidioc_default(file, fh, + use_fh_prio ? v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0, + cmd, arg); + } + +done: + if (debug) { + if (write_only && debug > V4L2_DEBUG_IOCTL) { + if (ret < 0) + printk(KERN_DEBUG "%s: error %ld\n", + video_device_node_name(vfd), ret); + return ret; + } + v4l_printk_ioctl(video_device_node_name(vfd), cmd); + if (ret < 0) + pr_cont(": error %ld\n", ret); + else if (debug == V4L2_DEBUG_IOCTL) + pr_cont("\n"); + else if (_IOC_DIR(cmd) == _IOC_NONE) + info->debug(arg, write_only); + else { + pr_cont(": "); + info->debug(arg, write_only); } } return ret; } -/* In some cases, only a few fields are used as input, i.e. when the app sets - * "index" and then the driver fills in the rest of the structure for the thing - * with that index. We only need to copy up the first non-input field. */ -static unsigned long cmd_input_size(unsigned int cmd) -{ - /* Size of structure up to and including 'field' */ -#define CMDINSIZE(cmd, type, field) \ - case VIDIOC_##cmd: \ - return offsetof(struct v4l2_##type, field) + \ - sizeof(((struct v4l2_##type *)0)->field); - - switch (cmd) { - CMDINSIZE(ENUM_FMT, fmtdesc, type); - CMDINSIZE(G_FMT, format, type); - CMDINSIZE(QUERYBUF, buffer, length); - CMDINSIZE(G_PARM, streamparm, type); - CMDINSIZE(ENUMSTD, standard, index); - CMDINSIZE(ENUMINPUT, input, index); - CMDINSIZE(G_CTRL, control, id); - CMDINSIZE(G_TUNER, tuner, index); - CMDINSIZE(QUERYCTRL, queryctrl, id); - CMDINSIZE(QUERYMENU, querymenu, index); - CMDINSIZE(ENUMOUTPUT, output, index); - CMDINSIZE(G_MODULATOR, modulator, index); - CMDINSIZE(G_FREQUENCY, frequency, tuner); - CMDINSIZE(CROPCAP, cropcap, type); - CMDINSIZE(G_CROP, crop, type); - CMDINSIZE(ENUMAUDIO, audio, index); - CMDINSIZE(ENUMAUDOUT, audioout, index); - CMDINSIZE(ENCODER_CMD, encoder_cmd, flags); - CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags); - CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type); - CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); - CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); - default: - return _IOC_SIZE(cmd); - } -} - static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, void * __user *user_ptr, void ***kernel_ptr) { @@ -2219,7 +2235,20 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, err = -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) { - unsigned long n = cmd_input_size(cmd); + unsigned int n = _IOC_SIZE(cmd); + + /* + * In some cases, only a few fields are used as input, + * i.e. when the app sets "index" and then the driver + * fills in the rest of the structure for the thing + * with that index. We only need to copy up the first + * non-input field. + */ + if (v4l2_is_known_ioctl(cmd)) { + u32 flags = v4l2_ioctls[_IOC_NR(cmd)].flags; + if (flags & INFO_FL_CLEAR_MASK) + n = (flags & INFO_FL_CLEAR_MASK) >> 16; + } if (copy_from_user(parg, (void __user *)arg, n)) goto out; diff --git a/drivers/media/video/v4l2-mem2mem.c b/drivers/media/video/v4l2-mem2mem.c index 975d0fa938c6..97b48318aee1 100644 --- a/drivers/media/video/v4l2-mem2mem.c +++ b/drivers/media/video/v4l2-mem2mem.c @@ -19,6 +19,9 @@ #include <media/videobuf2-core.h> #include <media/v4l2-mem2mem.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-event.h> MODULE_DESCRIPTION("Mem to mem device framework for videobuf"); MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>"); @@ -407,11 +410,24 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct poll_table_struct *wait) { + struct video_device *vfd = video_devdata(file); + unsigned long req_events = poll_requested_events(wait); struct vb2_queue *src_q, *dst_q; struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; unsigned int rc = 0; unsigned long flags; + if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { + struct v4l2_fh *fh = file->private_data; + + if (v4l2_event_pending(fh)) + rc = POLLPRI; + else if (req_events & POLLPRI) + poll_wait(file, &fh->wait, wait); + if (!(req_events & (POLLOUT | POLLWRNORM | POLLIN | POLLRDNORM))) + return rc; + } + src_q = v4l2_m2m_get_src_vq(m2m_ctx); dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); @@ -422,7 +438,7 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, */ if ((!src_q->streaming || list_empty(&src_q->queued_list)) && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { - rc = POLLERR; + rc |= POLLERR; goto end; } diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index db6e859b93d4..9182f81deb5b 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -245,7 +245,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; - sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL; + sel.target = V4L2_SEL_TGT_CROP; rval = v4l2_subdev_call( sd, pad, get_selection, subdev_fh, &sel); @@ -274,7 +274,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; - sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL; + sel.target = V4L2_SEL_TGT_CROP; sel.r = crop->rect; rval = v4l2_subdev_call( diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index 308e150a39bc..eb404c2ce270 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -963,7 +963,7 @@ static int viacam_do_try_fmt(struct via_camera *cam, upix->pixelformat = f->pixelformat; viacam_fmt_pre(upix, spix); - v4l2_fill_mbus_format(&mbus_fmt, upix, f->mbus_code); + v4l2_fill_mbus_format(&mbus_fmt, spix, f->mbus_code); ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(spix, &mbus_fmt); viacam_fmt_post(upix, spix); diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index ffdf59cfe405..bf7a326b1cdc 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -359,11 +359,6 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, break; } - if (vb->input != UNSET) { - b->flags |= V4L2_BUF_FLAG_INPUT; - b->input = vb->input; - } - b->field = vb->field; b->timestamp = vb->ts; b->bytesused = vb->size; @@ -402,7 +397,6 @@ int __videobuf_mmap_setup(struct videobuf_queue *q, break; q->bufs[i]->i = i; - q->bufs[i]->input = UNSET; q->bufs[i]->memory = memory; q->bufs[i]->bsize = bsize; switch (memory) { @@ -566,16 +560,6 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) goto done; } - if (b->flags & V4L2_BUF_FLAG_INPUT) { - if (b->input >= q->inputs) { - dprintk(1, "qbuf: wrong input.\n"); - goto done; - } - buf->input = b->input; - } else { - buf->input = UNSET; - } - switch (b->memory) { case V4L2_MEMORY_MMAP: if (0 == buf->baddr) { diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index b6b5cc1a43cb..3a43ba0959bf 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -40,7 +40,7 @@ struct videobuf_dma_contig_memory { static int __videobuf_dc_alloc(struct device *dev, struct videobuf_dma_contig_memory *mem, - unsigned long size, unsigned long flags) + unsigned long size, gfp_t flags) { mem->size = size; if (mem->cached) { @@ -56,7 +56,7 @@ static int __videobuf_dc_alloc(struct device *dev, dev_err(dev, "dma_map_single failed\n"); free_pages_exact(mem->vaddr, mem->size); - mem->vaddr = 0; + mem->vaddr = NULL; return err; } } @@ -359,32 +359,43 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, size = vma->vm_end - vma->vm_start; size = (size < mem->size) ? size : mem->size; - if (!mem->cached) + if (!mem->cached) { vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - pos = (unsigned long)mem->vaddr; - - while (size > 0) { - page = virt_to_page((void *)pos); - if (NULL == page) { - dev_err(q->dev, "mmap: virt_to_page failed\n"); - __videobuf_dc_free(q->dev, mem); - goto error; - } - retval = vm_insert_page(vma, start, page); + retval = remap_pfn_range(vma, vma->vm_start, + mem->dma_handle >> PAGE_SHIFT, + size, vma->vm_page_prot); if (retval) { - dev_err(q->dev, "mmap: insert failed with error %d\n", - retval); - __videobuf_dc_free(q->dev, mem); + dev_err(q->dev, "mmap: remap failed with error %d. ", + retval); + dma_free_coherent(q->dev, mem->size, + mem->vaddr, mem->dma_handle); goto error; } - start += PAGE_SIZE; - pos += PAGE_SIZE; + } else { + pos = (unsigned long)mem->vaddr; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + while (size > 0) { + page = virt_to_page((void *)pos); + if (NULL == page) { + dev_err(q->dev, "mmap: virt_to_page failed\n"); + __videobuf_dc_free(q->dev, mem); + goto error; + } + retval = vm_insert_page(vma, start, page); + if (retval) { + dev_err(q->dev, "mmap: insert failed with error %d\n", + retval); + __videobuf_dc_free(q->dev, mem); + goto error; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } } vma->vm_ops = &videobuf_vm_ops; diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 9d4e9edbd2e7..268c7dd4f823 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -336,9 +336,9 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) struct vb2_queue *q = vb->vb2_queue; int ret; - /* Copy back data such as timestamp, flags, input, etc. */ + /* Copy back data such as timestamp, flags, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); - b->input = vb->v4l2_buf.input; + b->reserved2 = vb->v4l2_buf.reserved2; b->reserved = vb->v4l2_buf.reserved; if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) { @@ -454,7 +454,50 @@ static int __verify_mmap_ops(struct vb2_queue *q) } /** - * vb2_reqbufs() - Initiate streaming + * __verify_memory_type() - Check whether the memory type and buffer type + * passed to a buffer operation are compatible with the queue. + */ +static int __verify_memory_type(struct vb2_queue *q, + enum v4l2_memory memory, enum v4l2_buf_type type) +{ + if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR) { + dprintk(1, "reqbufs: unsupported memory type\n"); + return -EINVAL; + } + + if (type != q->type) { + dprintk(1, "reqbufs: requested type is incorrect\n"); + return -EINVAL; + } + + /* + * Make sure all the required memory ops for given memory type + * are available. + */ + if (memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { + dprintk(1, "reqbufs: MMAP for current setup unsupported\n"); + return -EINVAL; + } + + if (memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { + dprintk(1, "reqbufs: USERPTR for current setup unsupported\n"); + return -EINVAL; + } + + /* + * Place the busy tests at the end: -EBUSY can be ignored when + * create_bufs is called with count == 0, but count == 0 should still + * do the memory and type validation. + */ + if (q->fileio) { + dprintk(1, "reqbufs: file io in progress\n"); + return -EBUSY; + } + return 0; +} + +/** + * __reqbufs() - Initiate streaming * @q: videobuf2 queue * @req: struct passed from userspace to vidioc_reqbufs handler in driver * @@ -476,46 +519,16 @@ static int __verify_mmap_ops(struct vb2_queue *q) * The return values from this function are intended to be directly returned * from vidioc_reqbufs handler in driver. */ -int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) +static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) { unsigned int num_buffers, allocated_buffers, num_planes = 0; - int ret = 0; - - if (q->fileio) { - dprintk(1, "reqbufs: file io in progress\n"); - return -EBUSY; - } - - if (req->memory != V4L2_MEMORY_MMAP - && req->memory != V4L2_MEMORY_USERPTR) { - dprintk(1, "reqbufs: unsupported memory type\n"); - return -EINVAL; - } - - if (req->type != q->type) { - dprintk(1, "reqbufs: requested type is incorrect\n"); - return -EINVAL; - } + int ret; if (q->streaming) { dprintk(1, "reqbufs: streaming active\n"); return -EBUSY; } - /* - * Make sure all the required memory ops for given memory type - * are available. - */ - if (req->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { - dprintk(1, "reqbufs: MMAP for current setup unsupported\n"); - return -EINVAL; - } - - if (req->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { - dprintk(1, "reqbufs: USERPTR for current setup unsupported\n"); - return -EINVAL; - } - if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { /* * We already have buffers allocated, so first check if they @@ -595,10 +608,23 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return 0; } + +/** + * vb2_reqbufs() - Wrapper for __reqbufs() that also verifies the memory and + * type values. + * @q: videobuf2 queue + * @req: struct passed from userspace to vidioc_reqbufs handler in driver + */ +int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) +{ + int ret = __verify_memory_type(q, req->memory, req->type); + + return ret ? ret : __reqbufs(q, req); +} EXPORT_SYMBOL_GPL(vb2_reqbufs); /** - * vb2_create_bufs() - Allocate buffers and any required auxiliary structs + * __create_bufs() - Allocate buffers and any required auxiliary structs * @q: videobuf2 queue * @create: creation parameters, passed from userspace to vidioc_create_bufs * handler in driver @@ -612,40 +638,10 @@ EXPORT_SYMBOL_GPL(vb2_reqbufs); * The return values from this function are intended to be directly returned * from vidioc_create_bufs handler in driver. */ -int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) +static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) { unsigned int num_planes = 0, num_buffers, allocated_buffers; - int ret = 0; - - if (q->fileio) { - dprintk(1, "%s(): file io in progress\n", __func__); - return -EBUSY; - } - - if (create->memory != V4L2_MEMORY_MMAP - && create->memory != V4L2_MEMORY_USERPTR) { - dprintk(1, "%s(): unsupported memory type\n", __func__); - return -EINVAL; - } - - if (create->format.type != q->type) { - dprintk(1, "%s(): requested type is incorrect\n", __func__); - return -EINVAL; - } - - /* - * Make sure all the required memory ops for given memory type - * are available. - */ - if (create->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { - dprintk(1, "%s(): MMAP for current setup unsupported\n", __func__); - return -EINVAL; - } - - if (create->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { - dprintk(1, "%s(): USERPTR for current setup unsupported\n", __func__); - return -EINVAL; - } + int ret; if (q->num_buffers == VIDEO_MAX_FRAME) { dprintk(1, "%s(): maximum number of buffers already allocated\n", @@ -653,8 +649,6 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) return -ENOBUFS; } - create->index = q->num_buffers; - if (!q->num_buffers) { memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); @@ -675,9 +669,9 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) /* Finally, allocate buffers and video memory */ ret = __vb2_queue_alloc(q, create->memory, num_buffers, num_planes); - if (ret < 0) { - dprintk(1, "Memory allocation failed with error: %d\n", ret); - return ret; + if (ret == 0) { + dprintk(1, "Memory allocation failed\n"); + return -ENOMEM; } allocated_buffers = ret; @@ -708,7 +702,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) if (ret < 0) { __vb2_queue_free(q, allocated_buffers); - return ret; + return -ENOMEM; } /* @@ -719,6 +713,23 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) return 0; } + +/** + * vb2_create_bufs() - Wrapper for __create_bufs() that also verifies the + * memory and type values. + * @q: videobuf2 queue + * @create: creation parameters, passed from userspace to vidioc_create_bufs + * handler in driver + */ +int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) +{ + int ret = __verify_memory_type(q, create->memory, create->format.type); + + create->index = q->num_buffers; + if (create->count == 0) + return ret != -EBUSY ? ret : 0; + return ret ? ret : __create_bufs(q, create); +} EXPORT_SYMBOL_GPL(vb2_create_bufs); /** @@ -860,7 +871,6 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, vb->v4l2_buf.field = b->field; vb->v4l2_buf.timestamp = b->timestamp; - vb->v4l2_buf.input = b->input; vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; return 0; @@ -2115,6 +2125,263 @@ size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count, } EXPORT_SYMBOL_GPL(vb2_write); + +/* + * The following functions are not part of the vb2 core API, but are helper + * functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations + * and struct vb2_ops. + * They contain boilerplate code that most if not all drivers have to do + * and so they simplify the driver code. + */ + +/* The queue is busy if there is a owner and you are not that owner. */ +static inline bool vb2_queue_is_busy(struct video_device *vdev, struct file *file) +{ + return vdev->queue->owner && vdev->queue->owner != file->private_data; +} + +/* vb2 ioctl helpers */ + +int vb2_ioctl_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct video_device *vdev = video_devdata(file); + int res = __verify_memory_type(vdev->queue, p->memory, p->type); + + if (res) + return res; + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + res = __reqbufs(vdev->queue, p); + /* If count == 0, then the owner has released all buffers and he + is no longer owner of the queue. Otherwise we have a new owner. */ + if (res == 0) + vdev->queue->owner = p->count ? file->private_data : NULL; + return res; +} +EXPORT_SYMBOL_GPL(vb2_ioctl_reqbufs); + +int vb2_ioctl_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *p) +{ + struct video_device *vdev = video_devdata(file); + int res = __verify_memory_type(vdev->queue, p->memory, p->format.type); + + p->index = vdev->queue->num_buffers; + /* If count == 0, then just check if memory and type are valid. + Any -EBUSY result from __verify_memory_type can be mapped to 0. */ + if (p->count == 0) + return res != -EBUSY ? res : 0; + if (res) + return res; + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + res = __create_bufs(vdev->queue, p); + if (res == 0) + vdev->queue->owner = file->private_data; + return res; +} +EXPORT_SYMBOL_GPL(vb2_ioctl_create_bufs); + +int vb2_ioctl_prepare_buf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_prepare_buf(vdev->queue, p); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_prepare_buf); + +int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct video_device *vdev = video_devdata(file); + + /* No need to call vb2_queue_is_busy(), anyone can query buffers. */ + return vb2_querybuf(vdev->queue, p); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf); + +int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_qbuf(vdev->queue, p); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf); + +int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_dqbuf); + +int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_streamon(vdev->queue, i); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_streamon); + +int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_streamoff(vdev->queue, i); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_streamoff); + +/* v4l2_file_operations helpers */ + +int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *vdev = video_devdata(file); + + return vb2_mmap(vdev->queue, vma); +} +EXPORT_SYMBOL_GPL(vb2_fop_mmap); + +int vb2_fop_release(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + + if (file->private_data == vdev->queue->owner) { + vb2_queue_release(vdev->queue); + vdev->queue->owner = NULL; + } + return v4l2_fh_release(file); +} +EXPORT_SYMBOL_GPL(vb2_fop_release); + +ssize_t vb2_fop_write(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct video_device *vdev = video_devdata(file); + struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; + bool must_lock = !test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) && lock; + int err = -EBUSY; + + if (must_lock && mutex_lock_interruptible(lock)) + return -ERESTARTSYS; + if (vb2_queue_is_busy(vdev, file)) + goto exit; + err = vb2_write(vdev->queue, buf, count, ppos, + file->f_flags & O_NONBLOCK); + if (err >= 0) + vdev->queue->owner = file->private_data; +exit: + if (must_lock) + mutex_unlock(lock); + return err; +} +EXPORT_SYMBOL_GPL(vb2_fop_write); + +ssize_t vb2_fop_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct video_device *vdev = video_devdata(file); + struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; + bool must_lock = !test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) && vdev->lock; + int err = -EBUSY; + + if (must_lock && mutex_lock_interruptible(lock)) + return -ERESTARTSYS; + if (vb2_queue_is_busy(vdev, file)) + goto exit; + err = vb2_read(vdev->queue, buf, count, ppos, + file->f_flags & O_NONBLOCK); + if (err >= 0) + vdev->queue->owner = file->private_data; +exit: + if (must_lock) + mutex_unlock(lock); + return err; +} +EXPORT_SYMBOL_GPL(vb2_fop_read); + +unsigned int vb2_fop_poll(struct file *file, poll_table *wait) +{ + struct video_device *vdev = video_devdata(file); + struct vb2_queue *q = vdev->queue; + struct mutex *lock = q->lock ? q->lock : vdev->lock; + unsigned long req_events = poll_requested_events(wait); + unsigned res; + void *fileio; + /* Yuck. We really need to get rid of this flag asap. If it is + set, then the core took the serialization lock before calling + poll(). This is being phased out, but for now we have to handle + this case. */ + bool locked = test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags); + bool must_lock = false; + + /* Try to be smart: only lock if polling might start fileio, + otherwise locking will only introduce unwanted delays. */ + if (q->num_buffers == 0 && q->fileio == NULL) { + if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) && + (req_events & (POLLIN | POLLRDNORM))) + must_lock = true; + else if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) && + (req_events & (POLLOUT | POLLWRNORM))) + must_lock = true; + } + + /* If locking is needed, but this helper doesn't know how, then you + shouldn't be using this helper but you should write your own. */ + WARN_ON(must_lock && !locked && !lock); + + if (must_lock && !locked && lock && mutex_lock_interruptible(lock)) + return POLLERR; + + fileio = q->fileio; + + res = vb2_poll(vdev->queue, file, wait); + + /* If fileio was started, then we have a new queue owner. */ + if (must_lock && !fileio && q->fileio) + q->owner = file->private_data; + if (must_lock && !locked && lock) + mutex_unlock(lock); + return res; +} +EXPORT_SYMBOL_GPL(vb2_fop_poll); + +#ifndef CONFIG_MMU +unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct video_device *vdev = video_devdata(file); + + return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags); +} +EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area); +#endif + +/* vb2_ops helpers. Only use if vq->lock is non-NULL. */ + +void vb2_ops_wait_prepare(struct vb2_queue *vq) +{ + mutex_unlock(vq->lock); +} +EXPORT_SYMBOL_GPL(vb2_ops_wait_prepare); + +void vb2_ops_wait_finish(struct vb2_queue *vq) +{ + mutex_lock(vq->lock); +} +EXPORT_SYMBOL_GPL(vb2_ops_wait_finish); + MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2"); MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 08c10240e70f..a05494b71b20 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -188,6 +188,7 @@ struct vivi_dev { struct list_head vivi_devlist; struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler ctrl_handler; + struct video_device vdev; /* controls */ struct v4l2_ctrl *brightness; @@ -213,9 +214,6 @@ struct vivi_dev { spinlock_t slock; struct mutex mutex; - /* various device info */ - struct video_device *vfd; - struct vivi_dmaqueue vidq; /* Several counters */ @@ -232,7 +230,6 @@ struct vivi_dev { struct vivi_fmt *fmt; unsigned int width, height; struct vb2_queue vb_vidq; - enum v4l2_field field; unsigned int field_count; u8 bars[9][3]; @@ -625,7 +622,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) dev->mv_count += 2; - buf->vb.v4l2_buf.field = dev->field; + buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; dev->field_count++; buf->vb.v4l2_buf.sequence = dev->field_count >> 1; do_gettimeofday(&ts); @@ -769,7 +766,13 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, struct vivi_dev *dev = vb2_get_drv_priv(vq); unsigned long size; - size = dev->width * dev->height * dev->pixelsize; + if (fmt) + size = fmt->fmt.pix.sizeimage; + else + size = dev->width * dev->height * dev->pixelsize; + + if (size == 0) + return -EINVAL; if (0 == *nbuffers) *nbuffers = 32; @@ -792,27 +795,6 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, return 0; } -static int buffer_init(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - BUG_ON(NULL == dev->fmt); - - /* - * This callback is called once per buffer, after its allocation. - * - * Vivi does not allow changing format during streaming, but it is - * possible to do so when streaming is paused (i.e. in streamoff state). - * Buffers however are not freed when going into streamoff and so - * buffer size verification has to be done in buffer_prepare, on each - * qbuf. - * It would be best to move verification code here to buf_init and - * s_fmt though. - */ - - return 0; -} - static int buffer_prepare(struct vb2_buffer *vb) { struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); @@ -850,20 +832,6 @@ static int buffer_prepare(struct vb2_buffer *vb) return 0; } -static int buffer_finish(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - dprintk(dev, 1, "%s\n", __func__); - return 0; -} - -static void buffer_cleanup(struct vb2_buffer *vb) -{ - struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - dprintk(dev, 1, "%s\n", __func__); - -} - static void buffer_queue(struct vb2_buffer *vb) { struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); @@ -909,10 +877,7 @@ static void vivi_unlock(struct vb2_queue *vq) static struct vb2_ops vivi_video_qops = { .queue_setup = queue_setup, - .buf_init = buffer_init, .buf_prepare = buffer_prepare, - .buf_finish = buffer_finish, - .buf_cleanup = buffer_cleanup, .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, @@ -959,7 +924,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; - f->fmt.pix.field = dev->field; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = (f->fmt.pix.width * dev->fmt->depth) >> 3; @@ -978,25 +943,16 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { struct vivi_dev *dev = video_drvdata(file); struct vivi_fmt *fmt; - enum v4l2_field field; fmt = get_format(f); if (!fmt) { - dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", + dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", f->fmt.pix.pixelformat); - return -EINVAL; - } - - field = f->fmt.pix.field; - - if (field == V4L2_FIELD_ANY) { - field = V4L2_FIELD_INTERLACED; - } else if (V4L2_FIELD_INTERLACED != field) { - dprintk(dev, 1, "Field type invalid.\n"); - return -EINVAL; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + fmt = get_format(f); } - f->fmt.pix.field = field; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2, &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0); f->fmt.pix.bytesperline = @@ -1021,7 +977,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (ret < 0) return ret; - if (vb2_is_streaming(q)) { + if (vb2_is_busy(q)) { dprintk(dev, 1, "%s device busy\n", __func__); return -EBUSY; } @@ -1030,53 +986,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->pixelsize = dev->fmt->depth / 8; dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; - dev->field = f->fmt.pix.field; return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_reqbufs(&dev->vb_vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_querybuf(&dev->vb_vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_qbuf(&dev->vb_vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_streamon(&dev->vb_vidq, i); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct vivi_dev *dev = video_drvdata(file); - return vb2_streamoff(&dev->vb_vidq, i); -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) -{ - return 0; -} - /* only one input in this sample driver */ static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp) @@ -1085,7 +998,6 @@ static int vidioc_enum_input(struct file *file, void *priv, return -EINVAL; inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = V4L2_STD_525_60; sprintf(inp->name, "Camera %u", inp->index); return 0; } @@ -1145,58 +1057,6 @@ static int vivi_s_ctrl(struct v4l2_ctrl *ctrl) File operations for the device ------------------------------------------------------------------*/ -static ssize_t -vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct vivi_dev *dev = video_drvdata(file); - int err; - - dprintk(dev, 1, "read called\n"); - mutex_lock(&dev->mutex); - err = vb2_read(&dev->vb_vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - mutex_unlock(&dev->mutex); - return err; -} - -static unsigned int -vivi_poll(struct file *file, struct poll_table_struct *wait) -{ - struct vivi_dev *dev = video_drvdata(file); - struct vb2_queue *q = &dev->vb_vidq; - - dprintk(dev, 1, "%s\n", __func__); - return vb2_poll(q, file, wait); -} - -static int vivi_close(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct vivi_dev *dev = video_drvdata(file); - - dprintk(dev, 1, "close called (dev=%s), file %p\n", - video_device_node_name(vdev), file); - - if (v4l2_fh_is_singular_file(file)) - vb2_queue_release(&dev->vb_vidq); - return v4l2_fh_release(file); -} - -static int vivi_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct vivi_dev *dev = video_drvdata(file); - int ret; - - dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); - - ret = vb2_mmap(&dev->vb_vidq, vma); - dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, - ret); - return ret; -} - static const struct v4l2_ctrl_ops vivi_ctrl_ops = { .g_volatile_ctrl = vivi_g_volatile_ctrl, .s_ctrl = vivi_s_ctrl, @@ -1301,11 +1161,11 @@ static const struct v4l2_ctrl_config vivi_ctrl_int_menu = { static const struct v4l2_file_operations vivi_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .release = vivi_close, - .read = vivi_read, - .poll = vivi_poll, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = vivi_mmap, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops vivi_ioctl_ops = { @@ -1314,16 +1174,17 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = { .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, @@ -1333,10 +1194,7 @@ static struct video_device vivi_template = { .name = "vivi", .fops = &vivi_fops, .ioctl_ops = &vivi_ioctl_ops, - .release = video_device_release, - - .tvnorms = V4L2_STD_525_60, - .current_norm = V4L2_STD_NTSC_M, + .release = video_device_release_empty, }; /* ----------------------------------------------------------------- @@ -1354,8 +1212,8 @@ static int vivi_release(void) dev = list_entry(list, struct vivi_dev, vivi_devlist); v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(dev->vfd)); - video_unregister_device(dev->vfd); + video_device_node_name(&dev->vdev)); + video_unregister_device(&dev->vdev); v4l2_device_unregister(&dev->v4l2_dev); v4l2_ctrl_handler_free(&dev->ctrl_handler); kfree(dev); @@ -1440,14 +1298,11 @@ static int __init vivi_create_instance(int inst) INIT_LIST_HEAD(&dev->vidq.active); init_waitqueue_head(&dev->vidq.wq); - ret = -ENOMEM; - vfd = video_device_alloc(); - if (!vfd) - goto unreg_dev; - + vfd = &dev->vdev; *vfd = vivi_template; vfd->debug = debug; vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = q; set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); /* @@ -1455,26 +1310,19 @@ static int __init vivi_create_instance(int inst) * all fops and v4l2 ioctls. */ vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); if (ret < 0) - goto rel_vdev; - - video_set_drvdata(vfd, dev); + goto unreg_dev; /* Now that everything is fine, let's add it to device list */ list_add_tail(&dev->vivi_devlist, &vivi_devlist); - if (video_nr != -1) - video_nr++; - - dev->vfd = vfd; v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", video_device_node_name(vfd)); return 0; -rel_vdev: - video_device_release(vfd); unreg_dev: v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h index d7166afc255e..ca2754a3cd63 100644 --- a/drivers/media/video/zoran/zoran.h +++ b/drivers/media/video/zoran/zoran.h @@ -172,8 +172,10 @@ struct zoran_jpg_settings { struct v4l2_jpegcompression jpg_comp; /* JPEG-specific capture settings */ }; +struct zoran_fh; + struct zoran_mapping { - struct file *file; + struct zoran_fh *fh; int count; }; diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index c57310931810..c6ccdeb6d8d6 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -2811,7 +2811,7 @@ static void zoran_vm_close (struct vm_area_struct *vma) { struct zoran_mapping *map = vma->vm_private_data; - struct zoran_fh *fh = map->file->private_data; + struct zoran_fh *fh = map->fh; struct zoran *zr = fh->zr; int i; @@ -2938,7 +2938,7 @@ zoran_mmap (struct file *file, res = -ENOMEM; goto mmap_unlock_and_return; } - map->file = file; + map->fh = fh; map->count = 1; vma->vm_ops = &zoran_vm_ops; diff --git a/drivers/media/video/zoran/zr36016.c b/drivers/media/video/zoran/zr36016.c index 21c088ea9046..b87ddba8608f 100644 --- a/drivers/media/video/zoran/zr36016.c +++ b/drivers/media/video/zoran/zr36016.c @@ -40,10 +40,10 @@ /* v4l API */ /* headerfile of this module */ -#include"zr36016.h" +#include "zr36016.h" /* codec io API */ -#include"videocodec.h" +#include "videocodec.h" /* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */ diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index e44cb330bbc8..9afab35878b4 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -37,6 +37,10 @@ #include <linux/highmem.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-event.h> #include <media/videobuf-vmalloc.h> @@ -120,11 +124,6 @@ static struct usb_device_id device_table[] = { MODULE_DEVICE_TABLE(usb, device_table); -struct zr364xx_mode { - u32 color; /* output video color format */ - u32 brightness; /* brightness */ -}; - /* frame structure */ struct zr364xx_framei { unsigned long ulState; /* ulState:ZR364XX_READ_IDLE, @@ -173,7 +172,10 @@ static const struct zr364xx_fmt formats[] = { struct zr364xx_camera { struct usb_device *udev; /* save off the usb device pointer */ struct usb_interface *interface;/* the interface for this device */ - struct video_device *vdev; /* v4l video device */ + struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; + struct video_device vdev; /* v4l video device */ + struct v4l2_fh *owner; /* owns the streaming */ int nb; struct zr364xx_bufferi buffer; int skip; @@ -181,12 +183,9 @@ struct zr364xx_camera { int height; int method; struct mutex lock; - struct mutex open_lock; - int users; spinlock_t slock; struct zr364xx_dmaqueue vidq; - int resources; int last_frame; int cur_frame; unsigned long frame_count; @@ -197,8 +196,7 @@ struct zr364xx_camera { const struct zr364xx_fmt *fmt; struct videobuf_queue vb_vidq; - enum v4l2_buf_type type; - struct zr364xx_mode mode; + bool was_streaming; }; /* buffer for one video frame */ @@ -230,11 +228,6 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value, transfer_buffer, size, CTRL_TIMEOUT); kfree(transfer_buffer); - - if (status < 0) - dev_err(&udev->dev, - "Failed sending control message, error %d.\n", status); - return status; } @@ -468,6 +461,7 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) { struct zr364xx_camera *cam = video_drvdata(file); + int err = 0; _DBG("%s\n", __func__); @@ -477,17 +471,21 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count, if (!count) return -EINVAL; - if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - zr364xx_vidioc_streamon(file, cam, cam->type) == 0) { - DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count, - (int) *ppos); + if (mutex_lock_interruptible(&cam->lock)) + return -ERESTARTSYS; + + err = zr364xx_vidioc_streamon(file, file->private_data, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (err == 0) { + DBG("%s: reading %d bytes at pos %d.\n", __func__, + (int) count, (int) *ppos); /* NoMan Sux ! */ - return videobuf_read_one(&cam->vb_vidq, buf, count, ppos, + err = videobuf_read_one(&cam->vb_vidq, buf, count, ppos, file->f_flags & O_NONBLOCK); } - - return 0; + mutex_unlock(&cam->lock); + return err; } /* video buffer vmalloc implementation based partly on VIVI driver which is @@ -702,35 +700,6 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, return 0; } -static int res_get(struct zr364xx_camera *cam) -{ - /* is it free? */ - mutex_lock(&cam->lock); - if (cam->resources) { - /* no, someone else uses it */ - mutex_unlock(&cam->lock); - return 0; - } - /* it's free, grab it */ - cam->resources = 1; - _DBG("res: get\n"); - mutex_unlock(&cam->lock); - return 1; -} - -static inline int res_check(struct zr364xx_camera *cam) -{ - return cam->resources; -} - -static void res_free(struct zr364xx_camera *cam) -{ - mutex_lock(&cam->lock); - cam->resources = 0; - mutex_unlock(&cam->lock); - _DBG("res: put\n"); -} - static int zr364xx_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -740,9 +709,10 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cam->udev->product, sizeof(cap->card)); strlcpy(cap->bus_info, dev_name(&cam->udev->dev), sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -772,50 +742,18 @@ static int zr364xx_vidioc_s_input(struct file *file, void *priv, return 0; } -static int zr364xx_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) +static int zr364xx_s_ctrl(struct v4l2_ctrl *ctrl) { - struct zr364xx_camera *cam; - - if (file == NULL) - return -ENODEV; - cam = video_drvdata(file); - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->type = V4L2_CTRL_TYPE_INTEGER; - strcpy(c->name, "Brightness"); - c->minimum = 0; - c->maximum = 127; - c->step = 1; - c->default_value = cam->mode.brightness; - c->flags = 0; - break; - default: - return -EINVAL; - } - return 0; -} - -static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct zr364xx_camera *cam; + struct zr364xx_camera *cam = + container_of(ctrl->handler, struct zr364xx_camera, ctrl_handler); int temp; - if (file == NULL) - return -ENODEV; - cam = video_drvdata(file); - - switch (c->id) { + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - cam->mode.brightness = c->value; /* hardware brightness */ - mutex_lock(&cam->lock); send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0); - temp = (0x60 << 8) + 127 - cam->mode.brightness; + temp = (0x60 << 8) + 127 - ctrl->val; send_control_msg(cam->udev, 1, temp, 0, NULL, 0); - mutex_unlock(&cam->lock); break; default: return -EINVAL; @@ -824,25 +762,6 @@ static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv, return 0; } -static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct zr364xx_camera *cam; - - if (file == NULL) - return -ENODEV; - cam = video_drvdata(file); - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = cam->mode.brightness; - break; - default: - return -EINVAL; - } - return 0; -} - static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -888,7 +807,7 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; f->fmt.pix.priv = 0; DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), @@ -911,7 +830,7 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.height = cam->height; f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; f->fmt.pix.priv = 0; return 0; } @@ -936,7 +855,7 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, goto out; } - if (res_check(cam)) { + if (cam->owner) { DBG("%s can't change format after started\n", __func__); ret = -EBUSY; goto out; @@ -944,14 +863,13 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, cam->width = f->fmt.pix.width; cam->height = f->fmt.pix.height; - dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__, + DBG("%s: %dx%d mode selected\n", __func__, cam->width, cam->height); f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; f->fmt.pix.priv = 0; cam->vb_vidq.field = f->fmt.pix.field; - cam->mode.color = V4L2_PIX_FMT_JPEG; if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120) mode = 1; @@ -1015,10 +933,11 @@ out: static int zr364xx_vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { - int rc; struct zr364xx_camera *cam = video_drvdata(file); - rc = videobuf_reqbufs(&cam->vb_vidq, p); - return rc; + + if (cam->owner && cam->owner != priv) + return -EBUSY; + return videobuf_reqbufs(&cam->vb_vidq, p); } static int zr364xx_vidioc_querybuf(struct file *file, @@ -1038,6 +957,8 @@ static int zr364xx_vidioc_qbuf(struct file *file, int rc; struct zr364xx_camera *cam = video_drvdata(file); _DBG("%s\n", __func__); + if (cam->owner && cam->owner != priv) + return -EBUSY; rc = videobuf_qbuf(&cam->vb_vidq, p); return rc; } @@ -1049,6 +970,8 @@ static int zr364xx_vidioc_dqbuf(struct file *file, int rc; struct zr364xx_camera *cam = video_drvdata(file); _DBG("%s\n", __func__); + if (cam->owner && cam->owner != priv) + return -EBUSY; rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK); return rc; } @@ -1197,29 +1120,23 @@ static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam) return 0; } -static int zr364xx_vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) +static int zr364xx_prepare(struct zr364xx_camera *cam) { - struct zr364xx_camera *cam = video_drvdata(file); - int j; int res; + int i, j; - DBG("%s\n", __func__); - - if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&cam->udev->dev, "invalid fh type0\n"); - return -EINVAL; - } - if (cam->type != type) { - dev_err(&cam->udev->dev, "invalid fh type1\n"); - return -EINVAL; - } - - if (!res_get(cam)) { - dev_err(&cam->udev->dev, "stream busy\n"); - return -EBUSY; + for (i = 0; init[cam->method][i].size != -1; i++) { + res = send_control_msg(cam->udev, 1, init[cam->method][i].value, + 0, init[cam->method][i].bytes, + init[cam->method][i].size); + if (res < 0) { + dev_err(&cam->udev->dev, + "error during open sequence: %d\n", i); + return res; + } } + cam->skip = 2; cam->last_frame = -1; cam->cur_frame = 0; cam->frame_count = 0; @@ -1227,11 +1144,31 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv, cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE; cam->buffer.frame[j].cur_size = 0; } + v4l2_ctrl_handler_setup(&cam->ctrl_handler); + return 0; +} + +static int zr364xx_vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct zr364xx_camera *cam = video_drvdata(file); + int res; + + DBG("%s\n", __func__); + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (cam->owner && cam->owner != priv) + return -EBUSY; + + res = zr364xx_prepare(cam); + if (res) + return res; res = videobuf_streamon(&cam->vb_vidq); if (res == 0) { zr364xx_start_acquire(cam); - } else { - res_free(cam); + cam->owner = file->private_data; } return res; } @@ -1239,67 +1176,32 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv, static int zr364xx_vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - int res; struct zr364xx_camera *cam = video_drvdata(file); DBG("%s\n", __func__); - if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&cam->udev->dev, "invalid fh type0\n"); + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - } - if (cam->type != type) { - dev_err(&cam->udev->dev, "invalid fh type1\n"); - return -EINVAL; - } + if (cam->owner && cam->owner != priv) + return -EBUSY; zr364xx_stop_acquire(cam); - res = videobuf_streamoff(&cam->vb_vidq); - if (res < 0) - return res; - res_free(cam); - return 0; + return videobuf_streamoff(&cam->vb_vidq); } /* open the camera */ static int zr364xx_open(struct file *file) { - struct video_device *vdev = video_devdata(file); struct zr364xx_camera *cam = video_drvdata(file); - struct usb_device *udev = cam->udev; - int i, err; + int err; DBG("%s\n", __func__); - mutex_lock(&cam->open_lock); + if (mutex_lock_interruptible(&cam->lock)) + return -ERESTARTSYS; - if (cam->users) { - err = -EBUSY; + err = v4l2_fh_open(file); + if (err) goto out; - } - - for (i = 0; init[cam->method][i].size != -1; i++) { - err = - send_control_msg(udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - if (err < 0) { - dev_err(&cam->udev->dev, - "error during open sequence: %d\n", i); - goto out; - } - } - - cam->skip = 2; - cam->users++; - file->private_data = vdev; - cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - cam->fmt = formats; - - videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops, - NULL, &cam->slock, - cam->type, - V4L2_FIELD_NONE, - sizeof(struct zr364xx_buffer), cam, NULL); /* Added some delay here, since opening/closing the camera quickly, * like Ekiga does during its startup, can crash the webcam @@ -1308,29 +1210,20 @@ static int zr364xx_open(struct file *file) err = 0; out: - mutex_unlock(&cam->open_lock); + mutex_unlock(&cam->lock); DBG("%s: %d\n", __func__, err); return err; } -static void zr364xx_destroy(struct zr364xx_camera *cam) +static void zr364xx_release(struct v4l2_device *v4l2_dev) { + struct zr364xx_camera *cam = + container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev); unsigned long i; - if (!cam) { - printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__); - return; - } - mutex_lock(&cam->open_lock); - if (cam->vdev) - video_unregister_device(cam->vdev); - cam->vdev = NULL; - - /* stops the read pipe if it is running */ - if (cam->b_acquire) - zr364xx_stop_acquire(cam); + v4l2_device_unregister(&cam->v4l2_dev); - zr364xx_stop_readpipe(cam); + videobuf_mmap_free(&cam->vb_vidq); /* release sys buffers */ for (i = 0; i < FRAMES; i++) { @@ -1341,62 +1234,45 @@ static void zr364xx_destroy(struct zr364xx_camera *cam) cam->buffer.frame[i].lpvbits = NULL; } + v4l2_ctrl_handler_free(&cam->ctrl_handler); /* release transfer buffer */ kfree(cam->pipe->transfer_buffer); - cam->pipe->transfer_buffer = NULL; - mutex_unlock(&cam->open_lock); kfree(cam); - cam = NULL; } /* release the camera */ -static int zr364xx_release(struct file *file) +static int zr364xx_close(struct file *file) { struct zr364xx_camera *cam; struct usb_device *udev; - int i, err; + int i; DBG("%s\n", __func__); cam = video_drvdata(file); - if (!cam) - return -ENODEV; - - mutex_lock(&cam->open_lock); + mutex_lock(&cam->lock); udev = cam->udev; - /* turn off stream */ - if (res_check(cam)) { + if (file->private_data == cam->owner) { + /* turn off stream */ if (cam->b_acquire) zr364xx_stop_acquire(cam); videobuf_streamoff(&cam->vb_vidq); - res_free(cam); - } - - cam->users--; - file->private_data = NULL; - for (i = 0; i < 2; i++) { - err = - send_control_msg(udev, 1, init[cam->method][i].value, - 0, init[cam->method][i].bytes, - init[cam->method][i].size); - if (err < 0) { - dev_err(&udev->dev, "error during release sequence\n"); - goto out; + for (i = 0; i < 2; i++) { + send_control_msg(udev, 1, init[cam->method][i].value, + 0, init[cam->method][i].bytes, + init[cam->method][i].size); } + cam->owner = NULL; } /* Added some delay here, since opening/closing the camera quickly, * like Ekiga does during its startup, can crash the webcam */ mdelay(100); - err = 0; - -out: - mutex_unlock(&cam->open_lock); - - return err; + mutex_unlock(&cam->lock); + return v4l2_fh_release(file); } @@ -1424,21 +1300,24 @@ static unsigned int zr364xx_poll(struct file *file, { struct zr364xx_camera *cam = video_drvdata(file); struct videobuf_queue *q = &cam->vb_vidq; - _DBG("%s\n", __func__); + unsigned res = v4l2_ctrl_poll(file, wait); - if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return POLLERR; + _DBG("%s\n", __func__); - return videobuf_poll_stream(file, q, wait); + return res | videobuf_poll_stream(file, q, wait); } +static const struct v4l2_ctrl_ops zr364xx_ctrl_ops = { + .s_ctrl = zr364xx_s_ctrl, +}; + static const struct v4l2_file_operations zr364xx_fops = { .owner = THIS_MODULE, .open = zr364xx_open, - .release = zr364xx_release, + .release = zr364xx_close, .read = zr364xx_read, .mmap = zr364xx_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = zr364xx_poll, }; @@ -1453,20 +1332,20 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { .vidioc_s_input = zr364xx_vidioc_s_input, .vidioc_streamon = zr364xx_vidioc_streamon, .vidioc_streamoff = zr364xx_vidioc_streamoff, - .vidioc_queryctrl = zr364xx_vidioc_queryctrl, - .vidioc_g_ctrl = zr364xx_vidioc_g_ctrl, - .vidioc_s_ctrl = zr364xx_vidioc_s_ctrl, .vidioc_reqbufs = zr364xx_vidioc_reqbufs, .vidioc_querybuf = zr364xx_vidioc_querybuf, .vidioc_qbuf = zr364xx_vidioc_qbuf, .vidioc_dqbuf = zr364xx_vidioc_dqbuf, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device zr364xx_template = { .name = DRIVER_DESC, .fops = &zr364xx_fops, .ioctl_ops = &zr364xx_ioctl_ops, - .release = video_device_release, + .release = video_device_release_empty, }; @@ -1540,6 +1419,7 @@ static int zr364xx_probe(struct usb_interface *intf, struct zr364xx_camera *cam = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; + struct v4l2_ctrl_handler *hdl; int err; int i; @@ -1555,21 +1435,34 @@ static int zr364xx_probe(struct usb_interface *intf, dev_err(&udev->dev, "cam: out of memory !\n"); return -ENOMEM; } - /* save the init method used by this camera */ - cam->method = id->driver_info; - cam->vdev = video_device_alloc(); - if (cam->vdev == NULL) { - dev_err(&udev->dev, "cam->vdev: out of memory !\n"); + cam->v4l2_dev.release = zr364xx_release; + err = v4l2_device_register(&intf->dev, &cam->v4l2_dev); + if (err < 0) { + dev_err(&udev->dev, "couldn't register v4l2_device\n"); kfree(cam); - cam = NULL; - return -ENOMEM; + return err; } - memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template)); - cam->vdev->parent = &intf->dev; - video_set_drvdata(cam->vdev, cam); + hdl = &cam->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 1); + v4l2_ctrl_new_std(hdl, &zr364xx_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 127, 1, 64); + if (hdl->error) { + err = hdl->error; + dev_err(&udev->dev, "couldn't register control\n"); + goto fail; + } + /* save the init method used by this camera */ + cam->method = id->driver_info; + mutex_init(&cam->lock); + cam->vdev = zr364xx_template; + cam->vdev.lock = &cam->lock; + cam->vdev.v4l2_dev = &cam->v4l2_dev; + cam->vdev.ctrl_handler = &cam->ctrl_handler; + set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags); + video_set_drvdata(&cam->vdev, cam); if (debug) - cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; + cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; cam->udev = udev; @@ -1615,11 +1508,7 @@ static int zr364xx_probe(struct usb_interface *intf, header2[439] = cam->width / 256; header2[440] = cam->width % 256; - cam->users = 0; cam->nb = 0; - cam->mode.brightness = 64; - mutex_init(&cam->lock); - mutex_init(&cam->open_lock); DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf); @@ -1635,52 +1524,100 @@ static int zr364xx_probe(struct usb_interface *intf, } if (!cam->read_endpoint) { + err = -ENOMEM; dev_err(&intf->dev, "Could not find bulk-in endpoint\n"); - video_device_release(cam->vdev); - kfree(cam); - cam = NULL; - return -ENOMEM; + goto fail; } /* v4l */ INIT_LIST_HEAD(&cam->vidq.active); cam->vidq.cam = cam; - err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1); - if (err) { - dev_err(&udev->dev, "video_register_device failed\n"); - video_device_release(cam->vdev); - kfree(cam); - cam = NULL; - return err; - } usb_set_intfdata(intf, cam); /* load zr364xx board specific */ err = zr364xx_board_init(cam); - if (err) { - spin_lock_init(&cam->slock); - return err; - } + if (!err) + err = v4l2_ctrl_handler_setup(hdl); + if (err) + goto fail; spin_lock_init(&cam->slock); + cam->fmt = formats; + + videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops, + NULL, &cam->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_NONE, + sizeof(struct zr364xx_buffer), cam, &cam->lock); + + err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); + if (err) { + dev_err(&udev->dev, "video_register_device failed\n"); + goto fail; + } + dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n", - video_device_node_name(cam->vdev)); + video_device_node_name(&cam->vdev)); return 0; + +fail: + v4l2_ctrl_handler_free(hdl); + v4l2_device_unregister(&cam->v4l2_dev); + kfree(cam); + return err; } static void zr364xx_disconnect(struct usb_interface *intf) { struct zr364xx_camera *cam = usb_get_intfdata(intf); - videobuf_mmap_free(&cam->vb_vidq); + + mutex_lock(&cam->lock); usb_set_intfdata(intf, NULL); dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n"); - zr364xx_destroy(cam); + video_unregister_device(&cam->vdev); + v4l2_device_disconnect(&cam->v4l2_dev); + + /* stops the read pipe if it is running */ + if (cam->b_acquire) + zr364xx_stop_acquire(cam); + + zr364xx_stop_readpipe(cam); + mutex_unlock(&cam->lock); + v4l2_device_put(&cam->v4l2_dev); } +#ifdef CONFIG_PM +static int zr364xx_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct zr364xx_camera *cam = usb_get_intfdata(intf); + + cam->was_streaming = cam->b_acquire; + if (!cam->was_streaming) + return 0; + zr364xx_stop_acquire(cam); + zr364xx_stop_readpipe(cam); + return 0; +} + +static int zr364xx_resume(struct usb_interface *intf) +{ + struct zr364xx_camera *cam = usb_get_intfdata(intf); + int res; + + if (!cam->was_streaming) + return 0; + + zr364xx_start_readpipe(cam); + res = zr364xx_prepare(cam); + if (!res) + zr364xx_start_acquire(cam); + return res; +} +#endif /**********************/ /* Module integration */ @@ -1690,6 +1627,11 @@ static struct usb_driver zr364xx_driver = { .name = "zr364xx", .probe = zr364xx_probe, .disconnect = zr364xx_disconnect, +#ifdef CONFIG_PM + .suspend = zr364xx_suspend, + .resume = zr364xx_resume, + .reset_resume = zr364xx_resume, +#endif .id_table = device_table }; |