[media] V4L: Use NULL pointer instead of plain integer in v4l2-ctrls.c file
[deliverable/linux.git] / drivers / media / video / v4l2-ctrls.c
index 18015c0a8d312c49554b9c5f211f6978250be5f2..b6a2ee71e5c300cead8a4d77cb4e627c687a476e 100644 (file)
@@ -230,6 +230,19 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                "Aperture Priority Mode",
                NULL
        };
+       static const char * const camera_exposure_metering[] = {
+               "Average",
+               "Center Weighted",
+               "Spot",
+               NULL
+       };
+       static const char * const camera_auto_focus_range[] = {
+               "Auto",
+               "Normal",
+               "Macro",
+               "Infinity",
+               NULL
+       };
        static const char * const colorfx[] = {
                "None",
                "Black & White",
@@ -241,6 +254,47 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                "Grass Green",
                "Skin Whiten",
                "Vivid",
+               "Aqua",
+               "Art Freeze",
+               "Silhouette",
+               "Solarization",
+               "Antique",
+               "Set Cb/Cr",
+               NULL
+       };
+       static const char * const auto_n_preset_white_balance[] = {
+               "Manual",
+               "Auto",
+               "Incandescent",
+               "Fluorescent",
+               "Fluorescent H",
+               "Horizon",
+               "Daylight",
+               "Flash",
+               "Cloudy",
+               "Shade",
+               NULL,
+       };
+       static const char * const camera_iso_sensitivity_auto[] = {
+               "Manual",
+               "Auto",
+               NULL
+       };
+       static const char * const scene_mode[] = {
+               "None",
+               "Backlight",
+               "Beach/Snow",
+               "Candle Light",
+               "Dusk/Dawn",
+               "Fall Colors",
+               "Fireworks",
+               "Landscape",
+               "Night",
+               "Party/Indoor",
+               "Portrait",
+               "Sports",
+               "Sunset",
+               "Text",
                NULL
        };
        static const char * const tune_preemphasis[] = {
@@ -410,8 +464,18 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                return camera_power_line_frequency;
        case V4L2_CID_EXPOSURE_AUTO:
                return camera_exposure_auto;
+       case V4L2_CID_EXPOSURE_METERING:
+               return camera_exposure_metering;
+       case V4L2_CID_AUTO_FOCUS_RANGE:
+               return camera_auto_focus_range;
        case V4L2_CID_COLORFX:
                return colorfx;
+       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+               return auto_n_preset_white_balance;
+       case V4L2_CID_ISO_SENSITIVITY_AUTO:
+               return camera_iso_sensitivity_auto;
+       case V4L2_CID_SCENE_MODE:
+               return scene_mode;
        case V4L2_CID_TUNE_PREEMPHASIS:
                return tune_preemphasis;
        case V4L2_CID_FLASH_LED_MODE:
@@ -493,6 +557,7 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:  return "Min Number of Capture Buffers";
        case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:   return "Min Number of Output Buffers";
        case V4L2_CID_ALPHA_COMPONENT:          return "Alpha Component";
+       case V4L2_CID_COLORFX_CBCR:             return "Color Effects, CbCr";
 
        /* MPEG controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -590,13 +655,26 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_TILT_ABSOLUTE:            return "Tilt, Absolute";
        case V4L2_CID_FOCUS_ABSOLUTE:           return "Focus, Absolute";
        case V4L2_CID_FOCUS_RELATIVE:           return "Focus, Relative";
-       case V4L2_CID_FOCUS_AUTO:               return "Focus, Automatic";
+       case V4L2_CID_FOCUS_AUTO:               return "Focus, Automatic Continuous";
        case V4L2_CID_ZOOM_ABSOLUTE:            return "Zoom, Absolute";
        case V4L2_CID_ZOOM_RELATIVE:            return "Zoom, Relative";
        case V4L2_CID_ZOOM_CONTINUOUS:          return "Zoom, Continuous";
        case V4L2_CID_PRIVACY:                  return "Privacy";
        case V4L2_CID_IRIS_ABSOLUTE:            return "Iris, Absolute";
        case V4L2_CID_IRIS_RELATIVE:            return "Iris, Relative";
+       case V4L2_CID_AUTO_EXPOSURE_BIAS:       return "Auto Exposure, Bias";
+       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset";
+       case V4L2_CID_WIDE_DYNAMIC_RANGE:       return "Wide Dynamic Range";
+       case V4L2_CID_IMAGE_STABILIZATION:      return "Image Stabilization";
+       case V4L2_CID_ISO_SENSITIVITY:          return "ISO Sensitivity";
+       case V4L2_CID_ISO_SENSITIVITY_AUTO:     return "ISO Sensitivity, Auto";
+       case V4L2_CID_EXPOSURE_METERING:        return "Exposure, Metering Mode";
+       case V4L2_CID_SCENE_MODE:               return "Scene Mode";
+       case V4L2_CID_3A_LOCK:                  return "3A Lock";
+       case V4L2_CID_AUTO_FOCUS_START:         return "Auto Focus, Start";
+       case V4L2_CID_AUTO_FOCUS_STOP:          return "Auto Focus, Stop";
+       case V4L2_CID_AUTO_FOCUS_STATUS:        return "Auto Focus, Status";
+       case V4L2_CID_AUTO_FOCUS_RANGE:         return "Auto Focus, Range";
 
        /* FM Radio Modulator control */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -644,6 +722,17 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality";
        case V4L2_CID_JPEG_ACTIVE_MARKER:       return "Active Markers";
 
+       /* Image source controls */
+       case V4L2_CID_IMAGE_SOURCE_CLASS:       return "Image Source Controls";
+       case V4L2_CID_VBLANK:                   return "Vertical Blanking";
+       case V4L2_CID_HBLANK:                   return "Horizontal Blanking";
+       case V4L2_CID_ANALOGUE_GAIN:            return "Analogue Gain";
+
+       /* Image processing controls */
+       case V4L2_CID_IMAGE_PROC_CLASS:         return "Image Processing Controls";
+       case V4L2_CID_LINK_FREQ:                return "Link Frequency";
+       case V4L2_CID_PIXEL_RATE:               return "Pixel Rate";
+
        default:
                return NULL;
        }
@@ -666,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:
@@ -688,6 +778,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
        case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
        case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+       case V4L2_CID_WIDE_DYNAMIC_RANGE:
+       case V4L2_CID_IMAGE_STABILIZATION:
                *type = V4L2_CTRL_TYPE_BOOLEAN;
                *min = 0;
                *max = *step = 1;
@@ -696,6 +788,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_TILT_RESET:
        case V4L2_CID_FLASH_STROBE:
        case V4L2_CID_FLASH_STROBE_STOP:
+       case V4L2_CID_AUTO_FOCUS_START:
+       case V4L2_CID_AUTO_FOCUS_STOP:
                *type = V4L2_CTRL_TYPE_BUTTON;
                *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
                *min = *max = *step = *def = 0;
@@ -719,7 +813,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_MPEG_STREAM_TYPE:
        case V4L2_CID_MPEG_STREAM_VBI_FMT:
        case V4L2_CID_EXPOSURE_AUTO:
+       case V4L2_CID_AUTO_FOCUS_RANGE:
        case V4L2_CID_COLORFX:
+       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
        case V4L2_CID_TUNE_PREEMPHASIS:
        case V4L2_CID_FLASH_LED_MODE:
        case V4L2_CID_FLASH_STROBE_SOURCE:
@@ -733,18 +829,30 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
        case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
        case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+       case V4L2_CID_ISO_SENSITIVITY_AUTO:
+       case V4L2_CID_EXPOSURE_METERING:
+       case V4L2_CID_SCENE_MODE:
                *type = V4L2_CTRL_TYPE_MENU;
                break;
+       case V4L2_CID_LINK_FREQ:
+               *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+               break;
        case V4L2_CID_RDS_TX_PS_NAME:
        case V4L2_CID_RDS_TX_RADIO_TEXT:
                *type = V4L2_CTRL_TYPE_STRING;
                break;
+       case V4L2_CID_ISO_SENSITIVITY:
+       case V4L2_CID_AUTO_EXPOSURE_BIAS:
+               *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+               break;
        case V4L2_CID_USER_CLASS:
        case V4L2_CID_CAMERA_CLASS:
        case V4L2_CID_MPEG_CLASS:
        case V4L2_CID_FM_TX_CLASS:
        case V4L2_CID_FLASH_CLASS:
        case V4L2_CID_JPEG_CLASS:
+       case V4L2_CID_IMAGE_SOURCE_CLASS:
+       case V4L2_CID_IMAGE_PROC_CLASS:
                *type = V4L2_CTRL_TYPE_CTRL_CLASS;
                /* You can neither read not write these */
                *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -759,6 +867,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
                break;
        case V4L2_CID_FLASH_FAULT:
        case V4L2_CID_JPEG_ACTIVE_MARKER:
+       case V4L2_CID_3A_LOCK:
+       case V4L2_CID_AUTO_FOCUS_STATUS:
                *type = V4L2_CTRL_TYPE_BITMASK;
                break;
        case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
@@ -768,8 +878,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
                break;
        case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
        case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+               *flags |= V4L2_CTRL_FLAG_VOLATILE;
+               /* Fall through */
+       case V4L2_CID_PIXEL_RATE:
                *type = V4L2_CTRL_TYPE_INTEGER64;
-               *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE;
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               *min = *max = *step = *def = 0;
                break;
        default:
                *type = V4L2_CTRL_TYPE_INTEGER;
@@ -817,6 +931,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
                *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
                break;
        case V4L2_CID_FLASH_STROBE_STATUS:
+       case V4L2_CID_AUTO_FOCUS_STATUS:
        case V4L2_CID_FLASH_READY:
                *flags |= V4L2_CTRL_FLAG_READ_ONLY;
                break;
@@ -852,7 +967,8 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change
                ev->u.ctrl.value64 = ctrl->cur.val64;
        ev->u.ctrl.minimum = ctrl->minimum;
        ev->u.ctrl.maximum = ctrl->maximum;
-       if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU
+           || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
                ev->u.ctrl.step = 1;
        else
                ev->u.ctrl.step = ctrl->step;
@@ -1083,10 +1199,13 @@ static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval)
                return 0;
 
        case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
                if (val < ctrl->minimum || val > ctrl->maximum)
                        return -ERANGE;
-               if (ctrl->qmenu[val][0] == '\0' ||
-                   (ctrl->menu_skip_mask & (1 << val)))
+               if (ctrl->menu_skip_mask & (1 << val))
+                       return -EINVAL;
+               if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
+                   ctrl->qmenu[val][0] == '\0')
                        return -EINVAL;
                return 0;
 
@@ -1114,6 +1233,7 @@ static int validate_new(const struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c
        case V4L2_CTRL_TYPE_INTEGER:
        case V4L2_CTRL_TYPE_BOOLEAN:
        case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
        case V4L2_CTRL_TYPE_BITMASK:
        case V4L2_CTRL_TYPE_BUTTON:
        case V4L2_CTRL_TYPE_CTRL_CLASS:
@@ -1152,7 +1272,8 @@ static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
 int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
                           unsigned nr_of_controls_hint)
 {
-       mutex_init(&hdl->lock);
+       hdl->lock = &hdl->_lock;
+       mutex_init(hdl->lock);
        INIT_LIST_HEAD(&hdl->ctrls);
        INIT_LIST_HEAD(&hdl->ctrl_refs);
        hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
@@ -1173,7 +1294,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
        if (hdl == NULL || hdl->buckets == NULL)
                return;
 
-       mutex_lock(&hdl->lock);
+       mutex_lock(hdl->lock);
        /* Free all nodes */
        list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
                list_del(&ref->node);
@@ -1190,7 +1311,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
        hdl->buckets = NULL;
        hdl->cached = NULL;
        hdl->error = 0;
-       mutex_unlock(&hdl->lock);
+       mutex_unlock(hdl->lock);
 }
 EXPORT_SYMBOL(v4l2_ctrl_handler_free);
 
@@ -1255,9 +1376,9 @@ static struct v4l2_ctrl_ref *find_ref_lock(
        struct v4l2_ctrl_ref *ref = NULL;
 
        if (hdl) {
-               mutex_lock(&hdl->lock);
+               mutex_lock(hdl->lock);
                ref = find_ref(hdl, id);
-               mutex_unlock(&hdl->lock);
+               mutex_unlock(hdl->lock);
        }
        return ref;
 }
@@ -1304,7 +1425,7 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
 
        INIT_LIST_HEAD(&new_ref->node);
 
-       mutex_lock(&hdl->lock);
+       mutex_lock(hdl->lock);
 
        /* Add immediately at the end of the list if the list is empty, or if
           the last element in the list has a lower ID.
@@ -1334,7 +1455,7 @@ insert_in_hash:
        hdl->buckets[bucket] = new_ref;
 
 unlock:
-       mutex_unlock(&hdl->lock);
+       mutex_unlock(hdl->lock);
        return 0;
 }
 
@@ -1343,7 +1464,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
                        const struct v4l2_ctrl_ops *ops,
                        u32 id, const char *name, enum v4l2_ctrl_type type,
                        s32 min, s32 max, u32 step, s32 def,
-                       u32 flags, const char * const *qmenu, void *priv)
+                       u32 flags, const char * const *qmenu,
+                       const s64 *qmenu_int, void *priv)
 {
        struct v4l2_ctrl *ctrl;
        unsigned sz_extra = 0;
@@ -1356,6 +1478,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
            (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
            (type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
            (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
+           (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL) ||
            (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
                handler_set_err(hdl, -ERANGE);
                return NULL;
@@ -1366,6 +1489,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
        }
        if ((type == V4L2_CTRL_TYPE_INTEGER ||
             type == V4L2_CTRL_TYPE_MENU ||
+            type == V4L2_CTRL_TYPE_INTEGER_MENU ||
             type == V4L2_CTRL_TYPE_BOOLEAN) &&
            (def < min || def > max)) {
                handler_set_err(hdl, -ERANGE);
@@ -1400,7 +1524,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
        ctrl->minimum = min;
        ctrl->maximum = max;
        ctrl->step = step;
-       ctrl->qmenu = qmenu;
+       if (type == V4L2_CTRL_TYPE_MENU)
+               ctrl->qmenu = qmenu;
+       else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
+               ctrl->qmenu_int = qmenu_int;
        ctrl->priv = priv;
        ctrl->cur.val = ctrl->val = ctrl->default_value = def;
 
@@ -1414,9 +1541,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
                kfree(ctrl);
                return NULL;
        }
-       mutex_lock(&hdl->lock);
+       mutex_lock(hdl->lock);
        list_add_tail(&ctrl->node, &hdl->ctrls);
-       mutex_unlock(&hdl->lock);
+       mutex_unlock(hdl->lock);
        return ctrl;
 }
 
@@ -1427,6 +1554,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
        struct v4l2_ctrl *ctrl;
        const char *name = cfg->name;
        const char * const *qmenu = cfg->qmenu;
+       const s64 *qmenu_int = cfg->qmenu_int;
        enum v4l2_ctrl_type type = cfg->type;
        u32 flags = cfg->flags;
        s32 min = cfg->min;
@@ -1438,18 +1566,24 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
                v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
                                                                &def, &flags);
 
-       is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU);
+       is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
+                  cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
        if (is_menu)
                WARN_ON(step);
        else
                WARN_ON(cfg->menu_skip_mask);
-       if (is_menu && qmenu == NULL)
+       if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL)
                qmenu = v4l2_ctrl_get_menu(cfg->id);
+       else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU &&
+                qmenu_int == NULL) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
 
        ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
                        type, min, max,
                        is_menu ? cfg->menu_skip_mask : step,
-                       def, flags, qmenu, priv);
+                       def, flags, qmenu, qmenu_int, priv);
        if (ctrl)
                ctrl->is_private = cfg->is_private;
        return ctrl;
@@ -1466,12 +1600,13 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
        u32 flags;
 
        v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
-       if (type == V4L2_CTRL_TYPE_MENU) {
+       if (type == V4L2_CTRL_TYPE_MENU
+           || type == V4L2_CTRL_TYPE_INTEGER_MENU) {
                handler_set_err(hdl, -EINVAL);
                return NULL;
        }
        return v4l2_ctrl_new(hdl, ops, id, name, type,
-                                   min, max, step, def, flags, NULL, NULL);
+                            min, max, step, def, flags, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std);
 
@@ -1493,10 +1628,31 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
                return NULL;
        }
        return v4l2_ctrl_new(hdl, ops, id, name, type,
-                                   0, max, mask, def, flags, qmenu, NULL);
+                            0, max, mask, def, flags, qmenu, NULL, NULL);
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
 
+/* Helper function for standard integer menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+                       const struct v4l2_ctrl_ops *ops,
+                       u32 id, s32 max, s32 def, const s64 *qmenu_int)
+{
+       const char *name;
+       enum v4l2_ctrl_type type;
+       s32 min;
+       s32 step;
+       u32 flags;
+
+       v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+       if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
+               handler_set_err(hdl, -EINVAL);
+               return NULL;
+       }
+       return v4l2_ctrl_new(hdl, ops, id, name, type,
+                            0, max, 0, def, flags, NULL, qmenu_int, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
+
 /* Add a control from another handler to this handler */
 struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl,
                                          struct v4l2_ctrl *ctrl)
@@ -1525,7 +1681,7 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
                return 0;
        if (hdl->error)
                return hdl->error;
-       mutex_lock(&add->lock);
+       mutex_lock(add->lock);
        list_for_each_entry(ref, &add->ctrl_refs, node) {
                struct v4l2_ctrl *ctrl = ref->ctrl;
 
@@ -1539,7 +1695,7 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
                if (ret)
                        break;
        }
-       mutex_unlock(&add->lock);
+       mutex_unlock(add->lock);
        return ret;
 }
 EXPORT_SYMBOL(v4l2_ctrl_add_handler);
@@ -1659,6 +1815,9 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
        case V4L2_CTRL_TYPE_MENU:
                printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
                break;
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+               printk(KERN_CONT "%lld", ctrl->qmenu_int[ctrl->cur.val]);
+               break;
        case V4L2_CTRL_TYPE_BITMASK:
                printk(KERN_CONT "0x%08x", ctrl->cur.val);
                break;
@@ -1700,11 +1859,11 @@ void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
        len = strlen(prefix);
        if (len && prefix[len - 1] != ' ')
                colon = ": ";
-       mutex_lock(&hdl->lock);
+       mutex_lock(hdl->lock);
        list_for_each_entry(ctrl, &hdl->ctrls, node)
                if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
                        log_ctrl(ctrl, prefix, colon);
-       mutex_unlock(&hdl->lock);
+       mutex_unlock(hdl->lock);
 }
 EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
 
@@ -1716,7 +1875,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
 
        if (hdl == NULL)
                return 0;
-       mutex_lock(&hdl->lock);
+       mutex_lock(hdl->lock);
        list_for_each_entry(ctrl, &hdl->ctrls, node)
                ctrl->done = false;
 
@@ -1741,7 +1900,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
                if (ret)
                        break;
        }
-       mutex_unlock(&hdl->lock);
+       mutex_unlock(hdl->lock);
        return ret;
 }
 EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
@@ -1756,7 +1915,7 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
        if (hdl == NULL)
                return -EINVAL;
 
-       mutex_lock(&hdl->lock);
+       mutex_lock(hdl->lock);
 
        /* Try to find it */
        ref = find_ref(hdl, id);
@@ -1781,7 +1940,7 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
                                        break;
                }
        }
-       mutex_unlock(&hdl->lock);
+       mutex_unlock(hdl->lock);
        if (!ref)
                return -EINVAL;
 
@@ -1795,7 +1954,8 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
        qc->minimum = ctrl->minimum;
        qc->maximum = ctrl->maximum;
        qc->default_value = ctrl->default_value;
-       if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU
+           || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
                qc->step = 1;
        else
                qc->step = ctrl->step;
@@ -1825,16 +1985,33 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
 
        qm->reserved = 0;
        /* Sanity checks */
-       if (ctrl->qmenu == NULL ||
-           i < ctrl->minimum || i > ctrl->maximum)
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_MENU:
+               if (ctrl->qmenu == NULL)
+                       return -EINVAL;
+               break;
+       case V4L2_CTRL_TYPE_INTEGER_MENU:
+               if (ctrl->qmenu_int == NULL)
+                       return -EINVAL;
+               break;
+       default:
                return -EINVAL;
+       }
+
+       if (i < ctrl->minimum || i > ctrl->maximum)
+               return -EINVAL;
+
        /* Use mask to see if this menu item should be skipped */
        if (ctrl->menu_skip_mask & (1 << i))
                return -EINVAL;
        /* Empty menu items should also be skipped */
-       if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
-               return -EINVAL;
-       strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
+               if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
+                       return -EINVAL;
+               strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+       } else {
+               qm->value = ctrl->qmenu_int[i];
+       }
        return 0;
 }
 EXPORT_SYMBOL(v4l2_querymenu);
@@ -1940,11 +2117,11 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
           belong to the same cluster. */
 
        /* This has to be done with the handler lock taken. */
-       mutex_lock(&hdl->lock);
+       mutex_lock(hdl->lock);
 
        /* 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;
 
@@ -1962,7 +2139,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                /* Point the mref helper to the current helper struct. */
                mref->helper = h;
        }
-       mutex_unlock(&hdl->lock);
+       mutex_unlock(hdl->lock);
        return 0;
 }
 
@@ -1996,7 +2173,8 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
                return class_check(hdl, cs->ctrl_class);
 
        if (cs->count > ARRAY_SIZE(helper)) {
-               helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+               helpers = kmalloc_array(cs->count, sizeof(helper[0]),
+                                       GFP_KERNEL);
                if (helpers == NULL)
                        return -ENOMEM;
        }
@@ -2218,7 +2396,8 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
                return class_check(hdl, cs->ctrl_class);
 
        if (cs->count > ARRAY_SIZE(helper)) {
-               helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+               helpers = kmalloc_array(cs->count, sizeof(helper[0]),
+                                       GFP_KERNEL);
                if (!helpers)
                        return -ENOMEM;
        }
@@ -2381,9 +2560,13 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
 
-void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
-                               struct v4l2_subscribed_event *sev)
+static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
 {
+       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
+       if (ctrl == NULL)
+               return -EINVAL;
+
        v4l2_ctrl_lock(ctrl);
        list_add_tail(&sev->node, &ctrl->ev_subs);
        if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
@@ -2394,20 +2577,46 @@ void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
                if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
                        changes |= V4L2_EVENT_CTRL_CH_VALUE;
                fill_event(&ev, ctrl, changes);
+               /* Mark the queue as active, allowing this initial
+                  event to be accepted. */
+               sev->elems = elems;
                v4l2_event_queue_fh(sev->fh, &ev);
        }
        v4l2_ctrl_unlock(ctrl);
+       return 0;
 }
-EXPORT_SYMBOL(v4l2_ctrl_add_event);
 
-void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
-                               struct v4l2_subscribed_event *sev)
+static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
 {
+       struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
        v4l2_ctrl_lock(ctrl);
        list_del(&sev->node);
        v4l2_ctrl_unlock(ctrl);
 }
-EXPORT_SYMBOL(v4l2_ctrl_del_event);
+
+void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
+{
+       u32 old_changes = old->u.ctrl.changes;
+
+       old->u.ctrl = new->u.ctrl;
+       old->u.ctrl.changes |= old_changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_replace);
+
+void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
+{
+       new->u.ctrl.changes |= old->u.ctrl.changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_merge);
+
+const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = {
+       .add = v4l2_ctrl_add_event,
+       .del = v4l2_ctrl_del_event,
+       .replace = v4l2_ctrl_replace,
+       .merge = v4l2_ctrl_merge,
+};
+EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops);
 
 int v4l2_ctrl_log_status(struct file *file, void *fh)
 {
@@ -2425,7 +2634,7 @@ int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
                                struct v4l2_event_subscription *sub)
 {
        if (sub->type == V4L2_EVENT_CTRL)
-               return v4l2_event_subscribe(fh, sub, 0);
+               return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
        return -EINVAL;
 }
 EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
This page took 0.035151 seconds and 5 git commands to generate.