diff options
author | Linus Torvalds | 2016-05-18 17:03:51 -0700 |
---|---|---|
committer | Linus Torvalds | 2016-05-18 17:03:51 -0700 |
commit | 19c5abcb74b712a7824ae7c55862932534e7dfec (patch) | |
tree | 006822aa663cb9ee886773e819d4793fe3947626 /include/media | |
parent | 675e0655c12209ba1f40af0dff7cd76b17a1315c (diff) | |
parent | aff093d4bbca91f543e24cde2135f393b8130f4b (diff) |
Merge tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- added support for Intersil/Techwell TW686x-based video capture cards
- v4l PCI skeleton driver moved to samples directory
- Documentation cleanups and improvements
- RC: reduced the memory footprint for IR raw events
- tpg: Export the tpg code from vivid as a module
- adv7180: Add device tree binding documentation
- lots of driver improvements and fixes
* tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (173 commits)
[media] exynos-gsc: avoid build warning without CONFIG_OF
[media] samples: v4l: from Documentation to samples directory
[media] dib0700: add USB ID for another STK8096-PVR ref design based card
[media] tvp5150: propagate I2C write error in .s_register callback
[media] tvp5150: return I2C write operation failure to callers
[media] em28xx: add support for Hauppauge WinTV-dualHD DVB tuner
[media] em28xx: add missing USB IDs
[media] update cx23885 and em28xx cardlists
[media] media: au0828 fix au0828_v4l2_device_register() to not unlock and free
[media] c8sectpfe: Rework firmware loading mechanism
[media] c8sectpfe: Demote print to dev_dbg
[media] c8sectpfe: Fix broken circular buffer wp management
[media] media-device: Simplify compat32 logic
[media] media: i2c: ths7303: remove redundant assignment on bt
[media] dvb-usb: hide unused functions
[media] xilinx-vipp: remove unnecessary of_node_put
[media] drivers/media/media-devnode: clear private_data before put_device()
[media] drivers/media/media-device: move debug log before _devnode_unregister()
[media] drivers/media/rc: postpone kfree(rc_dev)
[media] media/dvb-core: forward media_create_pad_links() return value
...
Diffstat (limited to 'include/media')
-rw-r--r-- | include/media/media-device.h | 13 | ||||
-rw-r--r-- | include/media/media-entity.h | 81 | ||||
-rw-r--r-- | include/media/rc-core.h | 18 | ||||
-rw-r--r-- | include/media/v4l2-dev.h | 3 | ||||
-rw-r--r-- | include/media/v4l2-device.h | 55 | ||||
-rw-r--r-- | include/media/v4l2-rect.h | 173 | ||||
-rw-r--r-- | include/media/v4l2-subdev.h | 8 | ||||
-rw-r--r-- | include/media/v4l2-tpg-colors.h | 68 | ||||
-rw-r--r-- | include/media/v4l2-tpg.h | 597 | ||||
-rw-r--r-- | include/media/vsp1.h | 23 |
10 files changed, 972 insertions, 67 deletions
diff --git a/include/media/media-device.h b/include/media/media-device.h index df74cfa7da4a..a9b33c47310d 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -25,7 +25,6 @@ #include <linux/list.h> #include <linux/mutex.h> -#include <linux/spinlock.h> #include <media/media-devnode.h> #include <media/media-entity.h> @@ -304,8 +303,7 @@ struct media_entity_notify { * @pads: List of registered pads * @links: List of registered links * @entity_notify: List of registered entity_notify callbacks - * @lock: Entities list lock - * @graph_mutex: Entities graph operation lock + * @graph_mutex: Protects access to struct media_device data * @pm_count_walk: Graph walk for power state walk. Access serialised using * graph_mutex. * @@ -313,7 +311,8 @@ struct media_entity_notify { * @enable_source: Enable Source Handler function pointer * @disable_source: Disable Source Handler function pointer * - * @link_notify: Link state change notification callback + * @link_notify: Link state change notification callback. This callback is + * called with the graph_mutex held. * * This structure represents an abstract high-level media device. It allows easy * access to entities and provides basic media device-level support. The @@ -357,7 +356,7 @@ struct media_device { u32 hw_revision; u32 driver_version; - u32 topology_version; + u64 topology_version; u32 id; struct ida entity_internal_idx; @@ -371,8 +370,6 @@ struct media_device { /* notify callback list invoked when a new entity is registered */ struct list_head entity_notify; - /* Protects the graph objects creation/removal */ - spinlock_t lock; /* Serializes graph operations. */ struct mutex graph_mutex; struct media_entity_graph pm_count_walk; @@ -494,7 +491,7 @@ int __must_check __media_device_register(struct media_device *mdev, #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE) /** - * __media_device_unregister() - Unegisters a media device element + * media_device_unregister() - Unregisters a media device element * * @mdev: pointer to struct &media_device * diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 6dc9e4e8cbd4..cbb266f7f2b5 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -179,6 +179,9 @@ struct media_pad { * @link_validate: Return whether a link is valid from the entity point of * view. The media_entity_pipeline_start() function * validates all links by calling this operation. Optional. + * + * Note: Those these callbacks are called with struct media_device.@graph_mutex + * mutex held. */ struct media_entity_operations { int (*link_setup)(struct media_entity *entity, @@ -188,10 +191,38 @@ struct media_entity_operations { }; /** + * enum media_entity_type - Media entity type + * + * @MEDIA_ENTITY_TYPE_BASE: + * The entity isn't embedded in another subsystem structure. + * @MEDIA_ENTITY_TYPE_VIDEO_DEVICE: + * The entity is embedded in a struct video_device instance. + * @MEDIA_ENTITY_TYPE_V4L2_SUBDEV: + * The entity is embedded in a struct v4l2_subdev instance. + * + * Media entity objects are often not instantiated directly, but the media + * entity structure is inherited by (through embedding) other subsystem-specific + * structures. The media entity type identifies the type of the subclass + * structure that implements a media entity instance. + * + * This allows runtime type identification of media entities and safe casting to + * the correct object type. For instance, a media entity structure instance + * embedded in a v4l2_subdev structure instance will have the type + * MEDIA_ENTITY_TYPE_V4L2_SUBDEV and can safely be cast to a v4l2_subdev + * structure using the container_of() macro. + */ +enum media_entity_type { + MEDIA_ENTITY_TYPE_BASE, + MEDIA_ENTITY_TYPE_VIDEO_DEVICE, + MEDIA_ENTITY_TYPE_V4L2_SUBDEV, +}; + +/** * struct media_entity - A media entity graph object. * * @graph_obj: Embedded structure containing the media object common data. * @name: Entity name. + * @obj_type: Type of the object that implements the media_entity. * @function: Entity main function, as defined in uapi/media.h * (MEDIA_ENT_F_*) * @flags: Entity flags, as defined in uapi/media.h (MEDIA_ENT_FL_*) @@ -220,6 +251,7 @@ struct media_entity_operations { struct media_entity { struct media_gobj graph_obj; /* must be first field in struct */ const char *name; + enum media_entity_type obj_type; u32 function; unsigned long flags; @@ -329,56 +361,29 @@ static inline u32 media_gobj_gen_id(enum media_gobj_type type, u64 local_id) } /** - * is_media_entity_v4l2_io() - identify if the entity main function - * is a V4L2 I/O - * + * is_media_entity_v4l2_video_device() - Check if the entity is a video_device * @entity: pointer to entity * - * Return: true if the entity main function is one of the V4L2 I/O types - * (video, VBI or SDR radio); false otherwise. + * Return: true if the entity is an instance of a video_device object and can + * safely be cast to a struct video_device using the container_of() macro, or + * false otherwise. */ -static inline bool is_media_entity_v4l2_io(struct media_entity *entity) +static inline bool is_media_entity_v4l2_video_device(struct media_entity *entity) { - if (!entity) - return false; - - switch (entity->function) { - case MEDIA_ENT_F_IO_V4L: - case MEDIA_ENT_F_IO_VBI: - case MEDIA_ENT_F_IO_SWRADIO: - return true; - default: - return false; - } + return entity && entity->obj_type == MEDIA_ENTITY_TYPE_VIDEO_DEVICE; } /** - * is_media_entity_v4l2_subdev - return true if the entity main function is - * associated with the V4L2 API subdev usage - * + * is_media_entity_v4l2_subdev() - Check if the entity is a v4l2_subdev * @entity: pointer to entity * - * This is an ancillary function used by subdev-based V4L2 drivers. - * It checks if the entity function is one of functions used by a V4L2 subdev, - * e. g. camera-relatef functions, analog TV decoder, TV tuner, V4L2 DSPs. + * Return: true if the entity is an instance of a v4l2_subdev object and can + * safely be cast to a struct v4l2_subdev using the container_of() macro, or + * false otherwise. */ static inline bool is_media_entity_v4l2_subdev(struct media_entity *entity) { - if (!entity) - return false; - - switch (entity->function) { - case MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: - case MEDIA_ENT_F_CAM_SENSOR: - case MEDIA_ENT_F_FLASH: - case MEDIA_ENT_F_LENS: - case MEDIA_ENT_F_ATV_DECODER: - case MEDIA_ENT_F_TUNER: - return true; - - default: - return false; - } + return entity && entity->obj_type == MEDIA_ENTITY_TYPE_V4L2_SUBDEV; } /** diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 0f77b3dffb37..b6586a91129c 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -215,12 +215,9 @@ enum raw_event_type { struct ir_raw_event { union { u32 duration; - - struct { - u32 carrier; - u8 duty_cycle; - }; + u32 carrier; }; + u8 duty_cycle; unsigned pulse:1; unsigned reset:1; @@ -228,13 +225,7 @@ struct ir_raw_event { unsigned carrier_report:1; }; -#define DEFINE_IR_RAW_EVENT(event) \ - struct ir_raw_event event = { \ - { .duration = 0 } , \ - .pulse = 0, \ - .reset = 0, \ - .timeout = 0, \ - .carrier_report = 0 } +#define DEFINE_IR_RAW_EVENT(event) struct ir_raw_event event = {} static inline void init_ir_raw_event(struct ir_raw_event *ev) { @@ -256,8 +247,7 @@ void ir_raw_event_set_idle(struct rc_dev *dev, bool idle); static inline void ir_raw_event_reset(struct rc_dev *dev) { - DEFINE_IR_RAW_EVENT(ev); - ev.reset = true; + struct ir_raw_event ev = { .reset = true }; ir_raw_event_store(dev, &ev); ir_raw_event_handle(dev); diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 76056ab5c5bd..25a3190308fb 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -92,6 +92,9 @@ struct video_device /* device ops */ const struct v4l2_file_operations *fops; + /* device capabilities as used in v4l2_capabilities */ + u32 device_caps; + /* sysfs */ struct device dev; /* v4l device */ struct cdev *cdev; /* character device */ diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index 9c581578783f..d5d45a8d3998 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -196,11 +196,64 @@ static inline void v4l2_subdev_notify(struct v4l2_subdev *sd, ##args); \ }) -#define v4l2_device_has_op(v4l2_dev, o, f) \ +/* + * Call the specified callback for all subdevs where grp_id & grpmsk != 0 + * (if grpmsk == `0, then match them all). Ignore any errors. Note that you + * cannot add or delete a subdev while walking the subdevs list. + */ +#define v4l2_device_mask_call_all(v4l2_dev, grpmsk, o, f, args...) \ + do { \ + struct v4l2_subdev *__sd; \ + \ + __v4l2_device_call_subdevs_p(v4l2_dev, __sd, \ + !(grpmsk) || (__sd->grp_id & (grpmsk)), o, f , \ + ##args); \ + } while (0) + +/* + * Call the specified callback for all subdevs where grp_id & grpmsk != 0 + * (if grpmsk == `0, then match them all). If the callback returns an error + * other than 0 or -ENOIOCTLCMD, then return with that error code. Note that + * you cannot add or delete a subdev while walking the subdevs list. + */ +#define v4l2_device_mask_call_until_err(v4l2_dev, grpmsk, o, f, args...) \ +({ \ + struct v4l2_subdev *__sd; \ + __v4l2_device_call_subdevs_until_err_p(v4l2_dev, __sd, \ + !(grpmsk) || (__sd->grp_id & (grpmsk)), o, f , \ + ##args); \ +}) + +/* + * Does any subdev with matching grpid (or all if grpid == 0) has the given + * op? + */ +#define v4l2_device_has_op(v4l2_dev, grpid, o, f) \ +({ \ + struct v4l2_subdev *__sd; \ + bool __result = false; \ + list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \ + if ((grpid) && __sd->grp_id != (grpid)) \ + continue; \ + if (v4l2_subdev_has_op(__sd, o, f)) { \ + __result = true; \ + break; \ + } \ + } \ + __result; \ +}) + +/* + * Does any subdev with matching grpmsk (or all if grpmsk == 0) has the given + * op? + */ +#define v4l2_device_mask_has_op(v4l2_dev, grpmsk, o, f) \ ({ \ struct v4l2_subdev *__sd; \ bool __result = false; \ list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \ + if ((grpmsk) && !(__sd->grp_id & (grpmsk))) \ + continue; \ if (v4l2_subdev_has_op(__sd, o, f)) { \ __result = true; \ break; \ diff --git a/include/media/v4l2-rect.h b/include/media/v4l2-rect.h new file mode 100644 index 000000000000..d2125f0cc7cd --- /dev/null +++ b/include/media/v4l2-rect.h @@ -0,0 +1,173 @@ +/* + * v4l2-rect.h - v4l2_rect helper functions + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _V4L2_RECT_H_ +#define _V4L2_RECT_H_ + +#include <linux/videodev2.h> + +/** + * v4l2_rect_set_size_to() - copy the width/height values. + * @r: rect whose width and height fields will be set + * @size: rect containing the width and height fields you need. + */ +static inline void v4l2_rect_set_size_to(struct v4l2_rect *r, + const struct v4l2_rect *size) +{ + r->width = size->width; + r->height = size->height; +} + +/** + * v4l2_rect_set_min_size() - width and height of r should be >= min_size. + * @r: rect whose width and height will be modified + * @min_size: rect containing the minimal width and height + */ +static inline void v4l2_rect_set_min_size(struct v4l2_rect *r, + const struct v4l2_rect *min_size) +{ + if (r->width < min_size->width) + r->width = min_size->width; + if (r->height < min_size->height) + r->height = min_size->height; +} + +/** + * v4l2_rect_set_max_size() - width and height of r should be <= max_size + * @r: rect whose width and height will be modified + * @max_size: rect containing the maximum width and height + */ +static inline void v4l2_rect_set_max_size(struct v4l2_rect *r, + const struct v4l2_rect *max_size) +{ + if (r->width > max_size->width) + r->width = max_size->width; + if (r->height > max_size->height) + r->height = max_size->height; +} + +/** + * v4l2_rect_map_inside()- r should be inside boundary. + * @r: rect that will be modified + * @boundary: rect containing the boundary for @r + */ +static inline void v4l2_rect_map_inside(struct v4l2_rect *r, + const struct v4l2_rect *boundary) +{ + v4l2_rect_set_max_size(r, boundary); + if (r->left < boundary->left) + r->left = boundary->left; + if (r->top < boundary->top) + r->top = boundary->top; + if (r->left + r->width > boundary->width) + r->left = boundary->width - r->width; + if (r->top + r->height > boundary->height) + r->top = boundary->height - r->height; +} + +/** + * v4l2_rect_same_size() - return true if r1 has the same size as r2 + * @r1: rectangle. + * @r2: rectangle. + * + * Return true if both rectangles have the same size. + */ +static inline bool v4l2_rect_same_size(const struct v4l2_rect *r1, + const struct v4l2_rect *r2) +{ + return r1->width == r2->width && r1->height == r2->height; +} + +/** + * v4l2_rect_intersect() - calculate the intersection of two rects. + * @r: intersection of @r1 and @r2. + * @r1: rectangle. + * @r2: rectangle. + */ +static inline void v4l2_rect_intersect(struct v4l2_rect *r, + const struct v4l2_rect *r1, + const struct v4l2_rect *r2) +{ + int right, bottom; + + r->top = max(r1->top, r2->top); + r->left = max(r1->left, r2->left); + bottom = min(r1->top + r1->height, r2->top + r2->height); + right = min(r1->left + r1->width, r2->left + r2->width); + r->height = max(0, bottom - r->top); + r->width = max(0, right - r->left); +} + +/** + * v4l2_rect_scale() - scale rect r by to/from + * @r: rect to be scaled. + * @from: from rectangle. + * @to: to rectangle. + * + * This scales rectangle @r horizontally by @to->width / @from->width and + * vertically by @to->height / @from->height. + * + * Typically @r is a rectangle inside @from and you want the rectangle as + * it would appear after scaling @from to @to. So the resulting @r will + * be the scaled rectangle inside @to. + */ +static inline void v4l2_rect_scale(struct v4l2_rect *r, + const struct v4l2_rect *from, + const struct v4l2_rect *to) +{ + if (from->width == 0 || from->height == 0) { + r->left = r->top = r->width = r->height = 0; + return; + } + r->left = (((r->left - from->left) * to->width) / from->width) & ~1; + r->width = ((r->width * to->width) / from->width) & ~1; + r->top = ((r->top - from->top) * to->height) / from->height; + r->height = (r->height * to->height) / from->height; +} + +/** + * v4l2_rect_overlap() - do r1 and r2 overlap? + * @r1: rectangle. + * @r2: rectangle. + * + * Returns true if @r1 and @r2 overlap. + */ +static inline bool v4l2_rect_overlap(const struct v4l2_rect *r1, + const struct v4l2_rect *r2) +{ + /* + * IF the left side of r1 is to the right of the right side of r2 OR + * the left side of r2 is to the right of the right side of r1 THEN + * they do not overlap. + */ + if (r1->left >= r2->left + r2->width || + r2->left >= r1->left + r1->width) + return false; + /* + * IF the top side of r1 is below the bottom of r2 OR + * the top side of r2 is below the bottom of r1 THEN + * they do not overlap. + */ + if (r1->top >= r2->top + r2->height || + r2->top >= r1->top + r1->height) + return false; + return true; +} + +#endif diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 11e2dfec0198..32fc7a4beb5e 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -572,6 +572,7 @@ struct v4l2_subdev_pad_config { /** * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations * + * @init_cfg: initialize the pad config to default values * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE ioctl handler * code. * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE ioctl handler @@ -607,6 +608,8 @@ struct v4l2_subdev_pad_config { * may be adjusted by the subdev driver to device capabilities. */ struct v4l2_subdev_pad_ops { + int (*init_cfg)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg); int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code); @@ -801,7 +804,12 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt); int v4l2_subdev_link_validate(struct media_link *link); + +struct v4l2_subdev_pad_config * +v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd); +void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg); #endif /* CONFIG_MEDIA_CONTROLLER */ + void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops); diff --git a/include/media/v4l2-tpg-colors.h b/include/media/v4l2-tpg-colors.h new file mode 100644 index 000000000000..2a88d1fae0cd --- /dev/null +++ b/include/media/v4l2-tpg-colors.h @@ -0,0 +1,68 @@ +/* + * v4l2-tpg-colors.h - Color definitions for the test pattern generator + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _V4L2_TPG_COLORS_H_ +#define _V4L2_TPG_COLORS_H_ + +struct color { + unsigned char r, g, b; +}; + +struct color16 { + int r, g, b; +}; + +enum tpg_color { + TPG_COLOR_CSC_WHITE, + TPG_COLOR_CSC_YELLOW, + TPG_COLOR_CSC_CYAN, + TPG_COLOR_CSC_GREEN, + TPG_COLOR_CSC_MAGENTA, + TPG_COLOR_CSC_RED, + TPG_COLOR_CSC_BLUE, + TPG_COLOR_CSC_BLACK, + TPG_COLOR_75_YELLOW, + TPG_COLOR_75_CYAN, + TPG_COLOR_75_GREEN, + TPG_COLOR_75_MAGENTA, + TPG_COLOR_75_RED, + TPG_COLOR_75_BLUE, + TPG_COLOR_100_WHITE, + TPG_COLOR_100_YELLOW, + TPG_COLOR_100_CYAN, + TPG_COLOR_100_GREEN, + TPG_COLOR_100_MAGENTA, + TPG_COLOR_100_RED, + TPG_COLOR_100_BLUE, + TPG_COLOR_100_BLACK, + TPG_COLOR_TEXTFG, + TPG_COLOR_TEXTBG, + TPG_COLOR_RANDOM, + TPG_COLOR_RAMP, + TPG_COLOR_MAX = TPG_COLOR_RAMP + 256 +}; + +extern const struct color tpg_colors[TPG_COLOR_MAX]; +extern const unsigned short tpg_rec709_to_linear[255 * 16 + 1]; +extern const unsigned short tpg_linear_to_rec709[255 * 16 + 1]; +extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1] + [V4L2_XFER_FUNC_SMPTE2084 + 1] + [TPG_COLOR_CSC_BLACK + 1]; + +#endif diff --git a/include/media/v4l2-tpg.h b/include/media/v4l2-tpg.h new file mode 100644 index 000000000000..329bebfa930c --- /dev/null +++ b/include/media/v4l2-tpg.h @@ -0,0 +1,597 @@ +/* + * v4l2-tpg.h - Test Pattern Generator + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _V4L2_TPG_H_ +#define _V4L2_TPG_H_ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/videodev2.h> +#include <media/v4l2-tpg-colors.h> + +enum tpg_pattern { + TPG_PAT_75_COLORBAR, + TPG_PAT_100_COLORBAR, + TPG_PAT_CSC_COLORBAR, + TPG_PAT_100_HCOLORBAR, + TPG_PAT_100_COLORSQUARES, + TPG_PAT_BLACK, + TPG_PAT_WHITE, + TPG_PAT_RED, + TPG_PAT_GREEN, + TPG_PAT_BLUE, + TPG_PAT_CHECKERS_16X16, + TPG_PAT_CHECKERS_2X2, + TPG_PAT_CHECKERS_1X1, + TPG_PAT_COLOR_CHECKERS_2X2, + TPG_PAT_COLOR_CHECKERS_1X1, + TPG_PAT_ALTERNATING_HLINES, + TPG_PAT_ALTERNATING_VLINES, + TPG_PAT_CROSS_1_PIXEL, + TPG_PAT_CROSS_2_PIXELS, + TPG_PAT_CROSS_10_PIXELS, + TPG_PAT_GRAY_RAMP, + + /* Must be the last pattern */ + TPG_PAT_NOISE, +}; + +extern const char * const tpg_pattern_strings[]; + +enum tpg_quality { + TPG_QUAL_COLOR, + TPG_QUAL_GRAY, + TPG_QUAL_NOISE +}; + +enum tpg_video_aspect { + TPG_VIDEO_ASPECT_IMAGE, + TPG_VIDEO_ASPECT_4X3, + TPG_VIDEO_ASPECT_14X9_CENTRE, + TPG_VIDEO_ASPECT_16X9_CENTRE, + TPG_VIDEO_ASPECT_16X9_ANAMORPHIC, +}; + +enum tpg_pixel_aspect { + TPG_PIXEL_ASPECT_SQUARE, + TPG_PIXEL_ASPECT_NTSC, + TPG_PIXEL_ASPECT_PAL, +}; + +enum tpg_move_mode { + TPG_MOVE_NEG_FAST, + TPG_MOVE_NEG, + TPG_MOVE_NEG_SLOW, + TPG_MOVE_NONE, + TPG_MOVE_POS_SLOW, + TPG_MOVE_POS, + TPG_MOVE_POS_FAST, +}; + +extern const char * const tpg_aspect_strings[]; + +#define TPG_MAX_PLANES 3 +#define TPG_MAX_PAT_LINES 8 + +struct tpg_data { + /* Source frame size */ + unsigned src_width, src_height; + /* Buffer height */ + unsigned buf_height; + /* Scaled output frame size */ + unsigned scaled_width; + u32 field; + bool field_alternate; + /* crop coordinates are frame-based */ + struct v4l2_rect crop; + /* compose coordinates are format-based */ + struct v4l2_rect compose; + /* border and square coordinates are frame-based */ + struct v4l2_rect border; + struct v4l2_rect square; + + /* Color-related fields */ + enum tpg_quality qual; + unsigned qual_offset; + u8 alpha_component; + bool alpha_red_only; + u8 brightness; + u8 contrast; + u8 saturation; + s16 hue; + u32 fourcc; + bool is_yuv; + u32 colorspace; + u32 xfer_func; + u32 ycbcr_enc; + /* + * Stores the actual transfer function, i.e. will never be + * V4L2_XFER_FUNC_DEFAULT. + */ + u32 real_xfer_func; + /* + * Stores the actual Y'CbCr encoding, i.e. will never be + * V4L2_YCBCR_ENC_DEFAULT. + */ + u32 real_ycbcr_enc; + u32 quantization; + /* + * Stores the actual quantization, i.e. will never be + * V4L2_QUANTIZATION_DEFAULT. + */ + u32 real_quantization; + enum tpg_video_aspect vid_aspect; + enum tpg_pixel_aspect pix_aspect; + unsigned rgb_range; + unsigned real_rgb_range; + unsigned buffers; + unsigned planes; + bool interleaved; + u8 vdownsampling[TPG_MAX_PLANES]; + u8 hdownsampling[TPG_MAX_PLANES]; + /* + * horizontal positions must be ANDed with this value to enforce + * correct boundaries for packed YUYV values. + */ + unsigned hmask[TPG_MAX_PLANES]; + /* Used to store the colors in native format, either RGB or YUV */ + u8 colors[TPG_COLOR_MAX][3]; + u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; + /* size in bytes for two pixels in each plane */ + unsigned twopixelsize[TPG_MAX_PLANES]; + unsigned bytesperline[TPG_MAX_PLANES]; + + /* Configuration */ + enum tpg_pattern pattern; + bool hflip; + bool vflip; + unsigned perc_fill; + bool perc_fill_blank; + bool show_border; + bool show_square; + bool insert_sav; + bool insert_eav; + + /* Test pattern movement */ + enum tpg_move_mode mv_hor_mode; + int mv_hor_count; + int mv_hor_step; + enum tpg_move_mode mv_vert_mode; + int mv_vert_count; + int mv_vert_step; + + bool recalc_colors; + bool recalc_lines; + bool recalc_square_border; + + /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */ + unsigned max_line_width; + u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; + u8 *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; + u8 *random_line[TPG_MAX_PLANES]; + u8 *contrast_line[TPG_MAX_PLANES]; + u8 *black_line[TPG_MAX_PLANES]; +}; + +void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h); +int tpg_alloc(struct tpg_data *tpg, unsigned max_w); +void tpg_free(struct tpg_data *tpg); +void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, + u32 field); +void tpg_log_status(struct tpg_data *tpg); + +void tpg_set_font(const u8 *f); +void tpg_gen_text(const struct tpg_data *tpg, + u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); +void tpg_calc_text_basep(struct tpg_data *tpg, + u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); +unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line); +void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, + unsigned p, u8 *vbuf); +void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, + unsigned p, u8 *vbuf); +bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); +void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, + const struct v4l2_rect *compose); + +static inline void tpg_s_pattern(struct tpg_data *tpg, enum tpg_pattern pattern) +{ + if (tpg->pattern == pattern) + return; + tpg->pattern = pattern; + tpg->recalc_colors = true; +} + +static inline void tpg_s_quality(struct tpg_data *tpg, + enum tpg_quality qual, unsigned qual_offset) +{ + if (tpg->qual == qual && tpg->qual_offset == qual_offset) + return; + tpg->qual = qual; + tpg->qual_offset = qual_offset; + tpg->recalc_colors = true; +} + +static inline enum tpg_quality tpg_g_quality(const struct tpg_data *tpg) +{ + return tpg->qual; +} + +static inline void tpg_s_alpha_component(struct tpg_data *tpg, + u8 alpha_component) +{ + if (tpg->alpha_component == alpha_component) + return; + tpg->alpha_component = alpha_component; + tpg->recalc_colors = true; +} + +static inline void tpg_s_alpha_mode(struct tpg_data *tpg, + bool red_only) +{ + if (tpg->alpha_red_only == red_only) + return; + tpg->alpha_red_only = red_only; + tpg->recalc_colors = true; +} + +static inline void tpg_s_brightness(struct tpg_data *tpg, + u8 brightness) +{ + if (tpg->brightness == brightness) + return; + tpg->brightness = brightness; + tpg->recalc_colors = true; +} + +static inline void tpg_s_contrast(struct tpg_data *tpg, + u8 contrast) +{ + if (tpg->contrast == contrast) + return; + tpg->contrast = contrast; + tpg->recalc_colors = true; +} + +static inline void tpg_s_saturation(struct tpg_data *tpg, + u8 saturation) +{ + if (tpg->saturation == saturation) + return; + tpg->saturation = saturation; + tpg->recalc_colors = true; +} + +static inline void tpg_s_hue(struct tpg_data *tpg, + s16 hue) +{ + if (tpg->hue == hue) + return; + tpg->hue = hue; + tpg->recalc_colors = true; +} + +static inline void tpg_s_rgb_range(struct tpg_data *tpg, + unsigned rgb_range) +{ + if (tpg->rgb_range == rgb_range) + return; + tpg->rgb_range = rgb_range; + tpg->recalc_colors = true; +} + +static inline void tpg_s_real_rgb_range(struct tpg_data *tpg, + unsigned rgb_range) +{ + if (tpg->real_rgb_range == rgb_range) + return; + tpg->real_rgb_range = rgb_range; + tpg->recalc_colors = true; +} + +static inline void tpg_s_colorspace(struct tpg_data *tpg, u32 colorspace) +{ + if (tpg->colorspace == colorspace) + return; + tpg->colorspace = colorspace; + tpg->recalc_colors = true; +} + +static inline u32 tpg_g_colorspace(const struct tpg_data *tpg) +{ + return tpg->colorspace; +} + +static inline void tpg_s_ycbcr_enc(struct tpg_data *tpg, u32 ycbcr_enc) +{ + if (tpg->ycbcr_enc == ycbcr_enc) + return; + tpg->ycbcr_enc = ycbcr_enc; + tpg->recalc_colors = true; +} + +static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg) +{ + return tpg->ycbcr_enc; +} + +static inline void tpg_s_xfer_func(struct tpg_data *tpg, u32 xfer_func) +{ + if (tpg->xfer_func == xfer_func) + return; + tpg->xfer_func = xfer_func; + tpg->recalc_colors = true; +} + +static inline u32 tpg_g_xfer_func(const struct tpg_data *tpg) +{ + return tpg->xfer_func; +} + +static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization) +{ + if (tpg->quantization == quantization) + return; + tpg->quantization = quantization; + tpg->recalc_colors = true; +} + +static inline u32 tpg_g_quantization(const struct tpg_data *tpg) +{ + return tpg->quantization; +} + +static inline unsigned tpg_g_buffers(const struct tpg_data *tpg) +{ + return tpg->buffers; +} + +static inline unsigned tpg_g_planes(const struct tpg_data *tpg) +{ + return tpg->interleaved ? 1 : tpg->planes; +} + +static inline bool tpg_g_interleaved(const struct tpg_data *tpg) +{ + return tpg->interleaved; +} + +static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane) +{ + return tpg->twopixelsize[plane]; +} + +static inline unsigned tpg_hdiv(const struct tpg_data *tpg, + unsigned plane, unsigned x) +{ + return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) * + tpg->twopixelsize[plane] / 2; +} + +static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x) +{ + return (x * tpg->scaled_width) / tpg->src_width; +} + +static inline unsigned tpg_hscale_div(const struct tpg_data *tpg, + unsigned plane, unsigned x) +{ + return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x)); +} + +static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) +{ + return tpg->bytesperline[plane]; +} + +static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl) +{ + unsigned p; + + if (tpg->buffers > 1) { + tpg->bytesperline[plane] = bpl; + return; + } + + for (p = 0; p < tpg_g_planes(tpg); p++) { + unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; + + tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p]; + } + if (tpg_g_interleaved(tpg)) + tpg->bytesperline[1] = tpg->bytesperline[0]; +} + + +static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane) +{ + unsigned w = 0; + unsigned p; + + if (tpg->buffers > 1) + return tpg_g_bytesperline(tpg, plane); + for (p = 0; p < tpg_g_planes(tpg); p++) { + unsigned plane_w = tpg_g_bytesperline(tpg, p); + + w += plane_w / tpg->vdownsampling[p]; + } + return w; +} + +static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, + unsigned plane, unsigned bpl) +{ + unsigned w = 0; + unsigned p; + + if (tpg->buffers > 1) + return bpl; + for (p = 0; p < tpg_g_planes(tpg); p++) { + unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; + + plane_w /= tpg->hdownsampling[p]; + w += plane_w / tpg->vdownsampling[p]; + } + return w; +} + +static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane) +{ + if (plane >= tpg_g_planes(tpg)) + return 0; + + return tpg_g_bytesperline(tpg, plane) * tpg->buf_height / + tpg->vdownsampling[plane]; +} + +static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) +{ + tpg->buf_height = h; +} + +static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate) +{ + tpg->field = field; + tpg->field_alternate = alternate; +} + +static inline void tpg_s_perc_fill(struct tpg_data *tpg, + unsigned perc_fill) +{ + tpg->perc_fill = perc_fill; +} + +static inline unsigned tpg_g_perc_fill(const struct tpg_data *tpg) +{ + return tpg->perc_fill; +} + +static inline void tpg_s_perc_fill_blank(struct tpg_data *tpg, + bool perc_fill_blank) +{ + tpg->perc_fill_blank = perc_fill_blank; +} + +static inline void tpg_s_video_aspect(struct tpg_data *tpg, + enum tpg_video_aspect vid_aspect) +{ + if (tpg->vid_aspect == vid_aspect) + return; + tpg->vid_aspect = vid_aspect; + tpg->recalc_square_border = true; +} + +static inline enum tpg_video_aspect tpg_g_video_aspect(const struct tpg_data *tpg) +{ + return tpg->vid_aspect; +} + +static inline void tpg_s_pixel_aspect(struct tpg_data *tpg, + enum tpg_pixel_aspect pix_aspect) +{ + if (tpg->pix_aspect == pix_aspect) + return; + tpg->pix_aspect = pix_aspect; + tpg->recalc_square_border = true; +} + +static inline void tpg_s_show_border(struct tpg_data *tpg, + bool show_border) +{ + tpg->show_border = show_border; +} + +static inline void tpg_s_show_square(struct tpg_data *tpg, + bool show_square) +{ + tpg->show_square = show_square; +} + +static inline void tpg_s_insert_sav(struct tpg_data *tpg, bool insert_sav) +{ + tpg->insert_sav = insert_sav; +} + +static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav) +{ + tpg->insert_eav = insert_eav; +} + +void tpg_update_mv_step(struct tpg_data *tpg); + +static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg, + enum tpg_move_mode mv_hor_mode) +{ + tpg->mv_hor_mode = mv_hor_mode; + tpg_update_mv_step(tpg); +} + +static inline void tpg_s_mv_vert_mode(struct tpg_data *tpg, + enum tpg_move_mode mv_vert_mode) +{ + tpg->mv_vert_mode = mv_vert_mode; + tpg_update_mv_step(tpg); +} + +static inline void tpg_init_mv_count(struct tpg_data *tpg) +{ + tpg->mv_hor_count = tpg->mv_vert_count = 0; +} + +static inline void tpg_update_mv_count(struct tpg_data *tpg, bool frame_is_field) +{ + tpg->mv_hor_count += tpg->mv_hor_step * (frame_is_field ? 1 : 2); + tpg->mv_vert_count += tpg->mv_vert_step * (frame_is_field ? 1 : 2); +} + +static inline void tpg_s_hflip(struct tpg_data *tpg, bool hflip) +{ + if (tpg->hflip == hflip) + return; + tpg->hflip = hflip; + tpg_update_mv_step(tpg); + tpg->recalc_lines = true; +} + +static inline bool tpg_g_hflip(const struct tpg_data *tpg) +{ + return tpg->hflip; +} + +static inline void tpg_s_vflip(struct tpg_data *tpg, bool vflip) +{ + tpg->vflip = vflip; +} + +static inline bool tpg_g_vflip(const struct tpg_data *tpg) +{ + return tpg->vflip; +} + +static inline bool tpg_pattern_is_static(const struct tpg_data *tpg) +{ + return tpg->pattern != TPG_PAT_NOISE && + tpg->mv_hor_mode == TPG_MOVE_NONE && + tpg->mv_vert_mode == TPG_MOVE_NONE; +} + +#endif diff --git a/include/media/vsp1.h b/include/media/vsp1.h index cc541753896f..3e654a0455bd 100644 --- a/include/media/vsp1.h +++ b/include/media/vsp1.h @@ -23,11 +23,22 @@ int vsp1_du_init(struct device *dev); int vsp1_du_setup_lif(struct device *dev, unsigned int width, unsigned int height); -int vsp1_du_atomic_begin(struct device *dev); -int vsp1_du_atomic_update(struct device *dev, unsigned int rpf, u32 pixelformat, - unsigned int pitch, dma_addr_t mem[2], - const struct v4l2_rect *src, - const struct v4l2_rect *dst); -int vsp1_du_atomic_flush(struct device *dev); +void vsp1_du_atomic_begin(struct device *dev); +int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf, + u32 pixelformat, unsigned int pitch, + dma_addr_t mem[2], const struct v4l2_rect *src, + const struct v4l2_rect *dst, unsigned int alpha, + unsigned int zpos); +void vsp1_du_atomic_flush(struct device *dev); + +static inline int vsp1_du_atomic_update(struct device *dev, + unsigned int rpf_index, u32 pixelformat, + unsigned int pitch, dma_addr_t mem[2], + const struct v4l2_rect *src, + const struct v4l2_rect *dst) +{ + return vsp1_du_atomic_update_ext(dev, rpf_index, pixelformat, pitch, + mem, src, dst, 255, 0); +} #endif /* __MEDIA_VSP1_H__ */ |