diff options
author | Hans de Goede <j.w.r.degoede@hhs.nl> | 2008-07-10 09:40:53 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:25:59 -0400 |
commit | dcef3237b652e1c02093feac0f443485a144f035 (patch) | |
tree | 81df2d056ef1c4179868512076d9339dbd98680a /drivers/media/video/gspca/gspca.c | |
parent | d0d0e39bc5912793405d3f84ffc982fa400e6cc0 (diff) |
V4L/DVB (8348): gspca: Add auto gain/exposure to sonixb and tas5110 / ov6650 sensors.
sonixb: Do auto gain for tas5110 / ov6650 sensors.
pac207: Move the auto_gain function to gspca.
gspca: New function gspca_auto_gain_n_exposure().
Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/gspca/gspca.c')
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 09f190c689d5..2ffb00ab0811 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -1790,6 +1790,94 @@ void gspca_disconnect(struct usb_interface *intf) | |||
1790 | } | 1790 | } |
1791 | EXPORT_SYMBOL(gspca_disconnect); | 1791 | EXPORT_SYMBOL(gspca_disconnect); |
1792 | 1792 | ||
1793 | /* -- cam driver utility functions -- */ | ||
1794 | |||
1795 | /* auto gain and exposure algorithm based on the knee algorithm described here: | ||
1796 | http://ytse.tricolour.net/docs/LowLightOptimization.html | ||
1797 | |||
1798 | Returns 0 if no changes were made, 1 if the gain and or exposure settings | ||
1799 | where changed. */ | ||
1800 | int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, | ||
1801 | int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee) | ||
1802 | { | ||
1803 | int i, steps, gain, orig_gain, exposure, orig_exposure, autogain; | ||
1804 | const struct ctrl *gain_ctrl = NULL; | ||
1805 | const struct ctrl *exposure_ctrl = NULL; | ||
1806 | const struct ctrl *autogain_ctrl = NULL; | ||
1807 | int retval = 0; | ||
1808 | |||
1809 | for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { | ||
1810 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) | ||
1811 | gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; | ||
1812 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) | ||
1813 | exposure_ctrl = &gspca_dev->sd_desc->ctrls[i]; | ||
1814 | if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN) | ||
1815 | autogain_ctrl = &gspca_dev->sd_desc->ctrls[i]; | ||
1816 | } | ||
1817 | if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) { | ||
1818 | PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called " | ||
1819 | "on cam without (auto)gain/exposure"); | ||
1820 | return 0; | ||
1821 | } | ||
1822 | |||
1823 | if (gain_ctrl->get(gspca_dev, &gain) || | ||
1824 | exposure_ctrl->get(gspca_dev, &exposure) || | ||
1825 | autogain_ctrl->get(gspca_dev, &autogain) || !autogain) | ||
1826 | return 0; | ||
1827 | |||
1828 | orig_gain = gain; | ||
1829 | orig_exposure = exposure; | ||
1830 | |||
1831 | /* If we are of a multiple of deadzone, do multiple steps to reach the | ||
1832 | desired lumination fast (with the risc of a slight overshoot) */ | ||
1833 | steps = abs(desired_avg_lum - avg_lum) / deadzone; | ||
1834 | |||
1835 | PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n", | ||
1836 | avg_lum, desired_avg_lum, steps); | ||
1837 | |||
1838 | for (i = 0; i < steps; i++) { | ||
1839 | if (avg_lum > desired_avg_lum) { | ||
1840 | if (gain > gain_knee) | ||
1841 | gain--; | ||
1842 | else if (exposure > exposure_knee) | ||
1843 | exposure--; | ||
1844 | else if (gain > gain_ctrl->qctrl.default_value) | ||
1845 | gain--; | ||
1846 | else if (exposure > exposure_ctrl->qctrl.minimum) | ||
1847 | exposure--; | ||
1848 | else if (gain > gain_ctrl->qctrl.minimum) | ||
1849 | gain--; | ||
1850 | else | ||
1851 | break; | ||
1852 | } else { | ||
1853 | if (gain < gain_ctrl->qctrl.default_value) | ||
1854 | gain++; | ||
1855 | else if (exposure < exposure_knee) | ||
1856 | exposure++; | ||
1857 | else if (gain < gain_knee) | ||
1858 | gain++; | ||
1859 | else if (exposure < exposure_ctrl->qctrl.maximum) | ||
1860 | exposure++; | ||
1861 | else if (gain < gain_ctrl->qctrl.maximum) | ||
1862 | gain++; | ||
1863 | else | ||
1864 | break; | ||
1865 | } | ||
1866 | } | ||
1867 | |||
1868 | if (gain != orig_gain) { | ||
1869 | gain_ctrl->set(gspca_dev, gain); | ||
1870 | retval = 1; | ||
1871 | } | ||
1872 | if (exposure != orig_exposure) { | ||
1873 | exposure_ctrl->set(gspca_dev, exposure); | ||
1874 | retval = 1; | ||
1875 | } | ||
1876 | |||
1877 | return retval; | ||
1878 | } | ||
1879 | EXPORT_SYMBOL(gspca_auto_gain_n_exposure); | ||
1880 | |||
1793 | /* -- module insert / remove -- */ | 1881 | /* -- module insert / remove -- */ |
1794 | static int __init gspca_init(void) | 1882 | static int __init gspca_init(void) |
1795 | { | 1883 | { |