diff options
author | Prabhakar Lad <prabhakar.csengg@gmail.com> | 2014-12-19 08:52:04 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-02-02 10:34:18 -0500 |
commit | 47e604c5ddf128b5102cfd5d88cd5e2f243e1c2f (patch) | |
tree | 06f82a3ad38c60db1f381ebe0fb65ec83445c5b1 /drivers/media/platform/ti-vpe | |
parent | 901c4ad64c53f4d29d7bd96f33d1d5aae55ad8d8 (diff) |
[media] media: ti-vpe: Use mem-to-mem ioctl helpers
1: Simplify the vpe mem-to-mem driver by using the m2m ioctl
and vb2 helpers.
2: Align and arranged the v4l2_ioctl_ops.
3: Fixes a typo.
4: Use of_match_ptr() instead of explicitly defining the macro
to NULL in case CONFIG_OF is not defined.
Signed-off-by: Lad, Prabhakar <prabhakar.csengg@gmail.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/platform/ti-vpe')
-rw-r--r-- | drivers/media/platform/ti-vpe/vpe.c | 157 |
1 files changed, 50 insertions, 107 deletions
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 968fb63caf94..c44760b705da 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
26 | #include <linux/ioctl.h> | 26 | #include <linux/ioctl.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/of.h> | ||
28 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
29 | #include <linux/pm_runtime.h> | 30 | #include <linux/pm_runtime.h> |
30 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
@@ -74,7 +75,7 @@ | |||
74 | #define VPE_DEF_BUFS_PER_JOB 1 /* default one buffer per batch job */ | 75 | #define VPE_DEF_BUFS_PER_JOB 1 /* default one buffer per batch job */ |
75 | 76 | ||
76 | /* | 77 | /* |
77 | * each VPE context can need up to 3 config desciptors, 7 input descriptors, | 78 | * each VPE context can need up to 3 config descriptors, 7 input descriptors, |
78 | * 3 output descriptors, and 10 control descriptors | 79 | * 3 output descriptors, and 10 control descriptors |
79 | */ | 80 | */ |
80 | #define VPE_DESC_LIST_SIZE (10 * VPDMA_DTD_DESC_SIZE + \ | 81 | #define VPE_DESC_LIST_SIZE (10 * VPDMA_DTD_DESC_SIZE + \ |
@@ -373,7 +374,6 @@ struct vpe_dev { | |||
373 | struct vpe_ctx { | 374 | struct vpe_ctx { |
374 | struct v4l2_fh fh; | 375 | struct v4l2_fh fh; |
375 | struct vpe_dev *dev; | 376 | struct vpe_dev *dev; |
376 | struct v4l2_m2m_ctx *m2m_ctx; | ||
377 | struct v4l2_ctrl_handler hdl; | 377 | struct v4l2_ctrl_handler hdl; |
378 | 378 | ||
379 | unsigned int field; /* current field */ | 379 | unsigned int field; /* current field */ |
@@ -887,10 +887,10 @@ static int job_ready(void *priv) | |||
887 | if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) | 887 | if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) |
888 | needed += 2; /* need additional two most recent fields */ | 888 | needed += 2; /* need additional two most recent fields */ |
889 | 889 | ||
890 | if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed) | 890 | if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < needed) |
891 | return 0; | 891 | return 0; |
892 | 892 | ||
893 | if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed) | 893 | if (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < needed) |
894 | return 0; | 894 | return 0; |
895 | 895 | ||
896 | return 1; | 896 | return 1; |
@@ -1100,15 +1100,15 @@ static void device_run(void *priv) | |||
1100 | struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; | 1100 | struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; |
1101 | 1101 | ||
1102 | if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) { | 1102 | if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) { |
1103 | ctx->src_vbs[2] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | 1103 | ctx->src_vbs[2] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
1104 | WARN_ON(ctx->src_vbs[2] == NULL); | 1104 | WARN_ON(ctx->src_vbs[2] == NULL); |
1105 | ctx->src_vbs[1] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | 1105 | ctx->src_vbs[1] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
1106 | WARN_ON(ctx->src_vbs[1] == NULL); | 1106 | WARN_ON(ctx->src_vbs[1] == NULL); |
1107 | } | 1107 | } |
1108 | 1108 | ||
1109 | ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | 1109 | ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
1110 | WARN_ON(ctx->src_vbs[0] == NULL); | 1110 | WARN_ON(ctx->src_vbs[0] == NULL); |
1111 | ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); | 1111 | ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); |
1112 | WARN_ON(ctx->dst_vb == NULL); | 1112 | WARN_ON(ctx->dst_vb == NULL); |
1113 | 1113 | ||
1114 | /* config descriptors */ | 1114 | /* config descriptors */ |
@@ -1334,7 +1334,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) | |||
1334 | finished: | 1334 | finished: |
1335 | vpe_dbg(ctx->dev, "finishing transaction\n"); | 1335 | vpe_dbg(ctx->dev, "finishing transaction\n"); |
1336 | ctx->bufs_completed = 0; | 1336 | ctx->bufs_completed = 0; |
1337 | v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); | 1337 | v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); |
1338 | handled: | 1338 | handled: |
1339 | return IRQ_HANDLED; | 1339 | return IRQ_HANDLED; |
1340 | } | 1340 | } |
@@ -1395,7 +1395,7 @@ static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
1395 | struct vpe_q_data *q_data; | 1395 | struct vpe_q_data *q_data; |
1396 | int i; | 1396 | int i; |
1397 | 1397 | ||
1398 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | 1398 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
1399 | if (!vq) | 1399 | if (!vq) |
1400 | return -EINVAL; | 1400 | return -EINVAL; |
1401 | 1401 | ||
@@ -1527,7 +1527,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) | |||
1527 | struct vb2_queue *vq; | 1527 | struct vb2_queue *vq; |
1528 | int i; | 1528 | int i; |
1529 | 1529 | ||
1530 | vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); | 1530 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
1531 | if (!vq) | 1531 | if (!vq) |
1532 | return -EINVAL; | 1532 | return -EINVAL; |
1533 | 1533 | ||
@@ -1739,52 +1739,6 @@ static int vpe_s_selection(struct file *file, void *fh, | |||
1739 | return set_srcdst_params(ctx); | 1739 | return set_srcdst_params(ctx); |
1740 | } | 1740 | } |
1741 | 1741 | ||
1742 | static int vpe_reqbufs(struct file *file, void *priv, | ||
1743 | struct v4l2_requestbuffers *reqbufs) | ||
1744 | { | ||
1745 | struct vpe_ctx *ctx = file2ctx(file); | ||
1746 | |||
1747 | return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); | ||
1748 | } | ||
1749 | |||
1750 | static int vpe_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
1751 | { | ||
1752 | struct vpe_ctx *ctx = file2ctx(file); | ||
1753 | |||
1754 | return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); | ||
1755 | } | ||
1756 | |||
1757 | static int vpe_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
1758 | { | ||
1759 | struct vpe_ctx *ctx = file2ctx(file); | ||
1760 | |||
1761 | return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); | ||
1762 | } | ||
1763 | |||
1764 | static int vpe_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
1765 | { | ||
1766 | struct vpe_ctx *ctx = file2ctx(file); | ||
1767 | |||
1768 | return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); | ||
1769 | } | ||
1770 | |||
1771 | static int vpe_streamon(struct file *file, void *priv, enum v4l2_buf_type type) | ||
1772 | { | ||
1773 | struct vpe_ctx *ctx = file2ctx(file); | ||
1774 | |||
1775 | return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); | ||
1776 | } | ||
1777 | |||
1778 | static int vpe_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) | ||
1779 | { | ||
1780 | struct vpe_ctx *ctx = file2ctx(file); | ||
1781 | |||
1782 | vpe_dump_regs(ctx->dev); | ||
1783 | vpdma_dump_regs(ctx->dev->vpdma); | ||
1784 | |||
1785 | return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); | ||
1786 | } | ||
1787 | |||
1788 | /* | 1742 | /* |
1789 | * defines number of buffers/frames a context can process with VPE before | 1743 | * defines number of buffers/frames a context can process with VPE before |
1790 | * switching to a different context. default value is 1 buffer per context | 1744 | * switching to a different context. default value is 1 buffer per context |
@@ -1814,14 +1768,14 @@ static const struct v4l2_ctrl_ops vpe_ctrl_ops = { | |||
1814 | }; | 1768 | }; |
1815 | 1769 | ||
1816 | static const struct v4l2_ioctl_ops vpe_ioctl_ops = { | 1770 | static const struct v4l2_ioctl_ops vpe_ioctl_ops = { |
1817 | .vidioc_querycap = vpe_querycap, | 1771 | .vidioc_querycap = vpe_querycap, |
1818 | 1772 | ||
1819 | .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt, | 1773 | .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt, |
1820 | .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt, | 1774 | .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt, |
1821 | .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt, | 1775 | .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt, |
1822 | .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt, | 1776 | .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt, |
1823 | 1777 | ||
1824 | .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt, | 1778 | .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt, |
1825 | .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt, | 1779 | .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt, |
1826 | .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, | 1780 | .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, |
1827 | .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, | 1781 | .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, |
@@ -1829,16 +1783,15 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = { | |||
1829 | .vidioc_g_selection = vpe_g_selection, | 1783 | .vidioc_g_selection = vpe_g_selection, |
1830 | .vidioc_s_selection = vpe_s_selection, | 1784 | .vidioc_s_selection = vpe_s_selection, |
1831 | 1785 | ||
1832 | .vidioc_reqbufs = vpe_reqbufs, | 1786 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
1833 | .vidioc_querybuf = vpe_querybuf, | 1787 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
1788 | .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, | ||
1789 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, | ||
1790 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, | ||
1791 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, | ||
1834 | 1792 | ||
1835 | .vidioc_qbuf = vpe_qbuf, | 1793 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
1836 | .vidioc_dqbuf = vpe_dqbuf, | 1794 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
1837 | |||
1838 | .vidioc_streamon = vpe_streamon, | ||
1839 | .vidioc_streamoff = vpe_streamoff, | ||
1840 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
1841 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
1842 | }; | 1795 | }; |
1843 | 1796 | ||
1844 | /* | 1797 | /* |
@@ -1910,7 +1863,23 @@ static int vpe_buf_prepare(struct vb2_buffer *vb) | |||
1910 | static void vpe_buf_queue(struct vb2_buffer *vb) | 1863 | static void vpe_buf_queue(struct vb2_buffer *vb) |
1911 | { | 1864 | { |
1912 | struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | 1865 | struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
1913 | v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); | 1866 | |
1867 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); | ||
1868 | } | ||
1869 | |||
1870 | static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) | ||
1871 | { | ||
1872 | /* currently we do nothing here */ | ||
1873 | |||
1874 | return 0; | ||
1875 | } | ||
1876 | |||
1877 | static void vpe_stop_streaming(struct vb2_queue *q) | ||
1878 | { | ||
1879 | struct vpe_ctx *ctx = vb2_get_drv_priv(q); | ||
1880 | |||
1881 | vpe_dump_regs(ctx->dev); | ||
1882 | vpdma_dump_regs(ctx->dev->vpdma); | ||
1914 | } | 1883 | } |
1915 | 1884 | ||
1916 | static struct vb2_ops vpe_qops = { | 1885 | static struct vb2_ops vpe_qops = { |
@@ -1919,6 +1888,8 @@ static struct vb2_ops vpe_qops = { | |||
1919 | .buf_queue = vpe_buf_queue, | 1888 | .buf_queue = vpe_buf_queue, |
1920 | .wait_prepare = vb2_ops_wait_prepare, | 1889 | .wait_prepare = vb2_ops_wait_prepare, |
1921 | .wait_finish = vb2_ops_wait_finish, | 1890 | .wait_finish = vb2_ops_wait_finish, |
1891 | .start_streaming = vpe_start_streaming, | ||
1892 | .stop_streaming = vpe_stop_streaming, | ||
1922 | }; | 1893 | }; |
1923 | 1894 | ||
1924 | static int queue_init(void *priv, struct vb2_queue *src_vq, | 1895 | static int queue_init(void *priv, struct vb2_queue *src_vq, |
@@ -1972,9 +1943,9 @@ static const struct v4l2_ctrl_config vpe_bufs_per_job = { | |||
1972 | static int vpe_open(struct file *file) | 1943 | static int vpe_open(struct file *file) |
1973 | { | 1944 | { |
1974 | struct vpe_dev *dev = video_drvdata(file); | 1945 | struct vpe_dev *dev = video_drvdata(file); |
1975 | struct vpe_ctx *ctx = NULL; | ||
1976 | struct vpe_q_data *s_q_data; | 1946 | struct vpe_q_data *s_q_data; |
1977 | struct v4l2_ctrl_handler *hdl; | 1947 | struct v4l2_ctrl_handler *hdl; |
1948 | struct vpe_ctx *ctx; | ||
1978 | int ret; | 1949 | int ret; |
1979 | 1950 | ||
1980 | vpe_dbg(dev, "vpe_open\n"); | 1951 | vpe_dbg(dev, "vpe_open\n"); |
@@ -2047,10 +2018,10 @@ static int vpe_open(struct file *file) | |||
2047 | if (ret) | 2018 | if (ret) |
2048 | goto exit_fh; | 2019 | goto exit_fh; |
2049 | 2020 | ||
2050 | ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); | 2021 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); |
2051 | 2022 | ||
2052 | if (IS_ERR(ctx->m2m_ctx)) { | 2023 | if (IS_ERR(ctx->fh.m2m_ctx)) { |
2053 | ret = PTR_ERR(ctx->m2m_ctx); | 2024 | ret = PTR_ERR(ctx->fh.m2m_ctx); |
2054 | goto exit_fh; | 2025 | goto exit_fh; |
2055 | } | 2026 | } |
2056 | 2027 | ||
@@ -2069,7 +2040,7 @@ static int vpe_open(struct file *file) | |||
2069 | ctx->load_mmrs = true; | 2040 | ctx->load_mmrs = true; |
2070 | 2041 | ||
2071 | vpe_dbg(dev, "created instance %p, m2m_ctx: %p\n", | 2042 | vpe_dbg(dev, "created instance %p, m2m_ctx: %p\n", |
2072 | ctx, ctx->m2m_ctx); | 2043 | ctx, ctx->fh.m2m_ctx); |
2073 | 2044 | ||
2074 | mutex_unlock(&dev->dev_mutex); | 2045 | mutex_unlock(&dev->dev_mutex); |
2075 | 2046 | ||
@@ -2107,7 +2078,7 @@ static int vpe_release(struct file *file) | |||
2107 | v4l2_fh_del(&ctx->fh); | 2078 | v4l2_fh_del(&ctx->fh); |
2108 | v4l2_fh_exit(&ctx->fh); | 2079 | v4l2_fh_exit(&ctx->fh); |
2109 | v4l2_ctrl_handler_free(&ctx->hdl); | 2080 | v4l2_ctrl_handler_free(&ctx->hdl); |
2110 | v4l2_m2m_ctx_release(ctx->m2m_ctx); | 2081 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
2111 | 2082 | ||
2112 | kfree(ctx); | 2083 | kfree(ctx); |
2113 | 2084 | ||
@@ -2124,39 +2095,13 @@ static int vpe_release(struct file *file) | |||
2124 | return 0; | 2095 | return 0; |
2125 | } | 2096 | } |
2126 | 2097 | ||
2127 | static unsigned int vpe_poll(struct file *file, | ||
2128 | struct poll_table_struct *wait) | ||
2129 | { | ||
2130 | struct vpe_ctx *ctx = file2ctx(file); | ||
2131 | struct vpe_dev *dev = ctx->dev; | ||
2132 | int ret; | ||
2133 | |||
2134 | mutex_lock(&dev->dev_mutex); | ||
2135 | ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); | ||
2136 | mutex_unlock(&dev->dev_mutex); | ||
2137 | return ret; | ||
2138 | } | ||
2139 | |||
2140 | static int vpe_mmap(struct file *file, struct vm_area_struct *vma) | ||
2141 | { | ||
2142 | struct vpe_ctx *ctx = file2ctx(file); | ||
2143 | struct vpe_dev *dev = ctx->dev; | ||
2144 | int ret; | ||
2145 | |||
2146 | if (mutex_lock_interruptible(&dev->dev_mutex)) | ||
2147 | return -ERESTARTSYS; | ||
2148 | ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); | ||
2149 | mutex_unlock(&dev->dev_mutex); | ||
2150 | return ret; | ||
2151 | } | ||
2152 | |||
2153 | static const struct v4l2_file_operations vpe_fops = { | 2098 | static const struct v4l2_file_operations vpe_fops = { |
2154 | .owner = THIS_MODULE, | 2099 | .owner = THIS_MODULE, |
2155 | .open = vpe_open, | 2100 | .open = vpe_open, |
2156 | .release = vpe_release, | 2101 | .release = vpe_release, |
2157 | .poll = vpe_poll, | 2102 | .poll = v4l2_m2m_fop_poll, |
2158 | .unlocked_ioctl = video_ioctl2, | 2103 | .unlocked_ioctl = video_ioctl2, |
2159 | .mmap = vpe_mmap, | 2104 | .mmap = v4l2_m2m_fop_mmap, |
2160 | }; | 2105 | }; |
2161 | 2106 | ||
2162 | static struct video_device vpe_videodev = { | 2107 | static struct video_device vpe_videodev = { |
@@ -2358,8 +2303,6 @@ static const struct of_device_id vpe_of_match[] = { | |||
2358 | }, | 2303 | }, |
2359 | {}, | 2304 | {}, |
2360 | }; | 2305 | }; |
2361 | #else | ||
2362 | #define vpe_of_match NULL | ||
2363 | #endif | 2306 | #endif |
2364 | 2307 | ||
2365 | static struct platform_driver vpe_pdrv = { | 2308 | static struct platform_driver vpe_pdrv = { |
@@ -2367,7 +2310,7 @@ static struct platform_driver vpe_pdrv = { | |||
2367 | .remove = vpe_remove, | 2310 | .remove = vpe_remove, |
2368 | .driver = { | 2311 | .driver = { |
2369 | .name = VPE_MODULE_NAME, | 2312 | .name = VPE_MODULE_NAME, |
2370 | .of_match_table = vpe_of_match, | 2313 | .of_match_table = of_match_ptr(vpe_of_match), |
2371 | }, | 2314 | }, |
2372 | }; | 2315 | }; |
2373 | 2316 | ||