From 3f03396918962b2f8b888d02b23cd1e0c88bf5e5 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 24 May 2016 09:16:06 +0200 Subject: media: vb2-dma-contig: add helper for setting dma max seg size Add a helper function for device drivers to set DMA's max_seg_size. Setting it to largest possible value lets DMA-mapping API always create contiguous mappings in DMA address space. This is essential for all devices, which use dma-contig videobuf2 memory allocator and shared buffers. Till now, the only case when vb2-dma-contig really 'worked' was a case where userspace provided USERPTR buffer, which was in fact mmaped contiguous buffer from the other v4l2/drm device. Also DMABUF made of contiguous buffer worked only when its exporter did not split it into several chunks in the scatter-list. Any other buffer failed, regardless of the arch/platform used and the presence of the IOMMU of the device bus. This patch provides interface to fix this issue. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki --- include/media/videobuf2-dma-contig.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index 2087c9a68be3..f7dc8401817e 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -35,6 +35,8 @@ static inline void *vb2_dma_contig_init_ctx(struct device *dev) } void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); +int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); +void vb2_dma_contig_clear_max_seg_size(struct device *dev); extern const struct vb2_mem_ops vb2_dma_contig_memops; -- cgit v1.2.3 From 59ce4039727ef408769ab0e1263ece893abe22bb Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 24 May 2016 15:31:24 +0200 Subject: of: reserved_mem: add support for using more than one region for given device This patch allows device drivers to initialize more than one reserved memory region assigned to given device. When driver needs to use more than one reserved memory region, it should allocate child devices and initialize regions by index for each of its child devices. Signed-off-by: Marek Szyprowski Acked-by: Rob Herring Signed-off-by: Sylwester Nawrocki --- drivers/of/of_reserved_mem.c | 85 +++++++++++++++++++++++++++++++---------- include/linux/of_reserved_mem.h | 25 ++++++++++-- 2 files changed, 86 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index ed01c0172e4a..04e4fe58fb0c 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MAX_RESERVED_REGIONS 16 static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; @@ -289,53 +290,95 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) return NULL; } +struct rmem_assigned_device { + struct device *dev; + struct reserved_mem *rmem; + struct list_head list; +}; + +static LIST_HEAD(of_rmem_assigned_device_list); +static DEFINE_MUTEX(of_rmem_assigned_device_mutex); + /** - * of_reserved_mem_device_init() - assign reserved memory region to given device + * of_reserved_mem_device_init_by_idx() - assign reserved memory region to + * given device + * @dev: Pointer to the device to configure + * @np: Pointer to the device_node with 'reserved-memory' property + * @idx: Index of selected region * - * This function assign memory region pointed by "memory-region" device tree - * property to the given device. + * This function assigns respective DMA-mapping operations based on reserved + * memory region specified by 'memory-region' property in @np node to the @dev + * device. When driver needs to use more than one reserved memory region, it + * should allocate child devices and initialize regions by name for each of + * child device. + * + * Returns error code or zero on success. */ -int of_reserved_mem_device_init(struct device *dev) +int of_reserved_mem_device_init_by_idx(struct device *dev, + struct device_node *np, int idx) { + struct rmem_assigned_device *rd; + struct device_node *target; struct reserved_mem *rmem; - struct device_node *np; int ret; - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return -ENODEV; + if (!np || !dev) + return -EINVAL; + + target = of_parse_phandle(np, "memory-region", idx); + if (!target) + return -EINVAL; - rmem = __find_rmem(np); - of_node_put(np); + rmem = __find_rmem(target); + of_node_put(target); if (!rmem || !rmem->ops || !rmem->ops->device_init) return -EINVAL; + rd = kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL); + if (!rd) + return -ENOMEM; + ret = rmem->ops->device_init(rmem, dev); - if (ret == 0) + if (ret == 0) { + rd->dev = dev; + rd->rmem = rmem; + + mutex_lock(&of_rmem_assigned_device_mutex); + list_add(&rd->list, &of_rmem_assigned_device_list); + mutex_unlock(&of_rmem_assigned_device_mutex); + dev_info(dev, "assigned reserved memory node %s\n", rmem->name); + } else { + kfree(rd); + } return ret; } -EXPORT_SYMBOL_GPL(of_reserved_mem_device_init); +EXPORT_SYMBOL_GPL(of_reserved_mem_device_init_by_idx); /** * of_reserved_mem_device_release() - release reserved memory device structures + * @dev: Pointer to the device to deconfigure * * This function releases structures allocated for memory region handling for * the given device. */ void of_reserved_mem_device_release(struct device *dev) { - struct reserved_mem *rmem; - struct device_node *np; - - np = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!np) - return; - - rmem = __find_rmem(np); - of_node_put(np); + struct rmem_assigned_device *rd; + struct reserved_mem *rmem = NULL; + + mutex_lock(&of_rmem_assigned_device_mutex); + list_for_each_entry(rd, &of_rmem_assigned_device_list, list) { + if (rd->dev == dev) { + rmem = rd->rmem; + list_del(&rd->list); + kfree(rd); + break; + } + } + mutex_unlock(&of_rmem_assigned_device_mutex); if (!rmem || !rmem->ops || !rmem->ops->device_release) return; diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index ad2f67054372..1779cda99ef7 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h @@ -1,7 +1,8 @@ #ifndef __OF_RESERVED_MEM_H #define __OF_RESERVED_MEM_H -struct device; +#include + struct of_phandle_args; struct reserved_mem_ops; @@ -28,14 +29,17 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem); _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn) #ifdef CONFIG_OF_RESERVED_MEM -int of_reserved_mem_device_init(struct device *dev); + +int of_reserved_mem_device_init_by_idx(struct device *dev, + struct device_node *np, int idx); void of_reserved_mem_device_release(struct device *dev); void fdt_init_reserved_mem(void); void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size); #else -static inline int of_reserved_mem_device_init(struct device *dev) +static inline int of_reserved_mem_device_init_by_idx(struct device *dev, + struct device_node *np, int idx) { return -ENOSYS; } @@ -46,4 +50,19 @@ static inline void fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size) { } #endif +/** + * of_reserved_mem_device_init() - assign reserved memory region to given device + * @dev: Pointer to the device to configure + * + * This function assigns respective DMA-mapping operations based on the first + * reserved memory region specified by 'memory-region' property in device tree + * node of the given device. + * + * Returns error code or zero on success. + */ +static inline int of_reserved_mem_device_init(struct device *dev) +{ + return of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0); +} + #endif /* __OF_RESERVED_MEM_H */ -- cgit v1.2.3 From dc19ed1571dd3882b35e12fdaf50acbcc9b69714 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Jun 2016 14:48:50 -0300 Subject: Update my main e-mails at the Kernel tree For the third time in three years, I'm changing my e-mail at Samsung. That's bad, as it may stop communications with me for a while. So, this time, I'll also the mchehab@kernel.org e-mail, as it remains stable since ever. Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- .mailmap | 1 + CREDITS | 1 + MAINTAINERS | 51 ++++++++++++++++++++++++++------------- drivers/media/v4l2-core/v4l2-mc.c | 2 +- include/media/v4l2-mc.h | 2 +- 5 files changed, 38 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/.mailmap b/.mailmap index 08b80428f583..4a293bea648d 100644 --- a/.mailmap +++ b/.mailmap @@ -89,6 +89,7 @@ Leonid I Ananiev Linas Vepstas Mark Brown Matthieu CASTET +Mauro Carvalho Chehab Mayuresh Janorkar Michael Buesch Michel Dänzer diff --git a/CREDITS b/CREDITS index 0f0bf22afe0c..2a3fbcd229e6 100644 --- a/CREDITS +++ b/CREDITS @@ -649,6 +649,7 @@ D: Configure, Menuconfig, xconfig N: Mauro Carvalho Chehab E: m.chehab@samsung.org +E: mchehab@osg.samsung.com E: mchehab@infradead.org D: Media subsystem (V4L/DVB) drivers and core D: EDAC drivers and EDAC 3.0 core rework diff --git a/MAINTAINERS b/MAINTAINERS index 45fad6cecc88..02299fd2db18 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2242,7 +2242,8 @@ F: include/net/ax25.h F: net/ax25/ AZ6007 DVB DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -2709,7 +2710,8 @@ F: Documentation/filesystems/btrfs.txt F: fs/btrfs/ BTTV VIDEO4LINUX DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -3343,7 +3345,8 @@ S: Maintained F: drivers/media/dvb-frontends/cx24120* CX88 VIDEO4LINUX DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -4290,7 +4293,8 @@ F: fs/ecryptfs/ EDAC-CORE M: Doug Thompson M: Borislav Petkov -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-edac@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next @@ -4335,7 +4339,8 @@ S: Maintained F: drivers/edac/e7xxx_edac.c EDAC-GHES -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/ghes_edac.c @@ -4359,19 +4364,22 @@ S: Maintained F: drivers/edac/i5000_edac.c EDAC-I5400 -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/i5400_edac.c EDAC-I7300 -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/i7300_edac.c EDAC-I7CORE -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/i7core_edac.c @@ -4408,7 +4416,8 @@ S: Maintained F: drivers/edac/r82600_edac.c EDAC-SBRIDGE -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/sb_edac.c @@ -4467,7 +4476,8 @@ S: Maintained F: drivers/net/ethernet/ibm/ehea/ EM28XX VIDEO4LINUX DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -7371,7 +7381,8 @@ S: Supported F: drivers/media/pci/netup_unidvb/* MEDIA INPUT INFRASTRUCTURE (V4L/DVB) -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab P: LinuxTV.org Project L: linux-media@vger.kernel.org W: https://linuxtv.org @@ -9863,7 +9874,8 @@ S: Odd Fixes F: drivers/media/i2c/saa6588* SAA7134 VIDEO4LINUX DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -10382,7 +10394,8 @@ S: Maintained F: drivers/media/radio/si4713/radio-usb-si4713.c SIANO DVB DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -11148,7 +11161,8 @@ S: Maintained F: drivers/media/i2c/tda9840* TEA5761 TUNER DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -11156,7 +11170,8 @@ S: Odd fixes F: drivers/media/tuners/tea5761.* TEA5767 TUNER DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -11543,7 +11558,8 @@ F: include/linux/shmem_fs.h F: mm/shmem.c TM6000 VIDEO4LINUX DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git @@ -12529,7 +12545,8 @@ S: Maintained F: arch/x86/entry/vdso/ XC2028/3028 TUNER DRIVER -M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab +M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c index ca94bded3386..8bef4331bd51 100644 --- a/drivers/media/v4l2-core/v4l2-mc.c +++ b/drivers/media/v4l2-core/v4l2-mc.c @@ -1,7 +1,7 @@ /* * Media Controller ancillary functions * - * Copyright (c) 2016 Mauro Carvalho Chehab + * Copyright (c) 2016 Mauro Carvalho Chehab * Copyright (C) 2016 Shuah Khan * Copyright (C) 2006-2010 Nokia Corporation * Copyright (c) 2016 Intel Corporation. diff --git a/include/media/v4l2-mc.h b/include/media/v4l2-mc.h index 98a938aabdfb..7a8d6037a4bb 100644 --- a/include/media/v4l2-mc.h +++ b/include/media/v4l2-mc.h @@ -1,7 +1,7 @@ /* * v4l2-mc.h - Media Controller V4L2 types and prototypes * - * Copyright (C) 2016 Mauro Carvalho Chehab + * Copyright (C) 2016 Mauro Carvalho Chehab * Copyright (C) 2006-2010 Nokia Corporation * Copyright (c) 2016 Intel Corporation. * -- cgit v1.2.3 From 163f1e93e995048b894c5fc86a6034d16beed740 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 23 Mar 2016 11:22:57 -0300 Subject: [media] media-devnode: fix namespace mess Along all media controller code, "mdev" is used to represent a pointer to struct media_device, and "devnode" for a pointer to struct media_devnode. However, inside media-devnode.[ch], "mdev" is used to represent a pointer to struct media_devnode. This is very confusing and may lead to development errors. So, let's change all occurrences at media-devnode.[ch] to also use "devnode" for such pointers. This patch doesn't make any functional changes. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-devnode.c | 110 +++++++++++++++++++++--------------------- include/media/media-devnode.h | 16 +++--- 2 files changed, 63 insertions(+), 63 deletions(-) (limited to 'include') diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index b66dc9d0766b..7481c9610945 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -59,21 +59,21 @@ static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); /* Called when the last user of the media device exits. */ static void media_devnode_release(struct device *cd) { - struct media_devnode *mdev = to_media_devnode(cd); + struct media_devnode *devnode = to_media_devnode(cd); mutex_lock(&media_devnode_lock); /* Delete the cdev on this minor as well */ - cdev_del(&mdev->cdev); + cdev_del(&devnode->cdev); /* Mark device node number as free */ - clear_bit(mdev->minor, media_devnode_nums); + clear_bit(devnode->minor, media_devnode_nums); mutex_unlock(&media_devnode_lock); /* Release media_devnode and perform other cleanups as needed. */ - if (mdev->release) - mdev->release(mdev); + if (devnode->release) + devnode->release(devnode); } static struct bus_type media_bus_type = { @@ -83,37 +83,37 @@ static struct bus_type media_bus_type = { static ssize_t media_read(struct file *filp, char __user *buf, size_t sz, loff_t *off) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp); - if (!mdev->fops->read) + if (!devnode->fops->read) return -EINVAL; - if (!media_devnode_is_registered(mdev)) + if (!media_devnode_is_registered(devnode)) return -EIO; - return mdev->fops->read(filp, buf, sz, off); + return devnode->fops->read(filp, buf, sz, off); } static ssize_t media_write(struct file *filp, const char __user *buf, size_t sz, loff_t *off) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp); - if (!mdev->fops->write) + if (!devnode->fops->write) return -EINVAL; - if (!media_devnode_is_registered(mdev)) + if (!media_devnode_is_registered(devnode)) return -EIO; - return mdev->fops->write(filp, buf, sz, off); + return devnode->fops->write(filp, buf, sz, off); } static unsigned int media_poll(struct file *filp, struct poll_table_struct *poll) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp); - if (!media_devnode_is_registered(mdev)) + if (!media_devnode_is_registered(devnode)) return POLLERR | POLLHUP; - if (!mdev->fops->poll) + if (!devnode->fops->poll) return DEFAULT_POLLMASK; - return mdev->fops->poll(filp, poll); + return devnode->fops->poll(filp, poll); } static long @@ -121,12 +121,12 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, long (*ioctl_func)(struct file *filp, unsigned int cmd, unsigned long arg)) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp); if (!ioctl_func) return -ENOTTY; - if (!media_devnode_is_registered(mdev)) + if (!media_devnode_is_registered(devnode)) return -EIO; return ioctl_func(filp, cmd, arg); @@ -134,9 +134,9 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp); - return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl); + return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl); } #ifdef CONFIG_COMPAT @@ -144,9 +144,9 @@ static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static long media_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp); - return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl); + return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl); } #endif /* CONFIG_COMPAT */ @@ -154,7 +154,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd, /* Override for the open function */ static int media_open(struct inode *inode, struct file *filp) { - struct media_devnode *mdev; + struct media_devnode *devnode; int ret; /* Check if the media device is available. This needs to be done with @@ -164,23 +164,23 @@ static int media_open(struct inode *inode, struct file *filp) * a crash. */ mutex_lock(&media_devnode_lock); - mdev = container_of(inode->i_cdev, struct media_devnode, cdev); + devnode = container_of(inode->i_cdev, struct media_devnode, cdev); /* return ENXIO if the media device has been removed already or if it is not registered anymore. */ - if (!media_devnode_is_registered(mdev)) { + if (!media_devnode_is_registered(devnode)) { mutex_unlock(&media_devnode_lock); return -ENXIO; } /* and increase the device refcount */ - get_device(&mdev->dev); + get_device(&devnode->dev); mutex_unlock(&media_devnode_lock); - filp->private_data = mdev; + filp->private_data = devnode; - if (mdev->fops->open) { - ret = mdev->fops->open(filp); + if (devnode->fops->open) { + ret = devnode->fops->open(filp); if (ret) { - put_device(&mdev->dev); + put_device(&devnode->dev); filp->private_data = NULL; return ret; } @@ -192,16 +192,16 @@ static int media_open(struct inode *inode, struct file *filp) /* Override for the release function */ static int media_release(struct inode *inode, struct file *filp) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp); - if (mdev->fops->release) - mdev->fops->release(filp); + if (devnode->fops->release) + devnode->fops->release(filp); filp->private_data = NULL; /* decrease the refcount unconditionally since the release() return value is ignored. */ - put_device(&mdev->dev); + put_device(&devnode->dev); return 0; } @@ -219,7 +219,7 @@ static const struct file_operations media_devnode_fops = { .llseek = no_llseek, }; -int __must_check media_devnode_register(struct media_devnode *mdev, +int __must_check media_devnode_register(struct media_devnode *devnode, struct module *owner) { int minor; @@ -237,55 +237,55 @@ int __must_check media_devnode_register(struct media_devnode *mdev, set_bit(minor, media_devnode_nums); mutex_unlock(&media_devnode_lock); - mdev->minor = minor; + devnode->minor = minor; /* Part 2: Initialize and register the character device */ - cdev_init(&mdev->cdev, &media_devnode_fops); - mdev->cdev.owner = owner; + cdev_init(&devnode->cdev, &media_devnode_fops); + devnode->cdev.owner = owner; - ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1); + ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1); if (ret < 0) { pr_err("%s: cdev_add failed\n", __func__); goto error; } /* Part 3: Register the media device */ - mdev->dev.bus = &media_bus_type; - mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor); - mdev->dev.release = media_devnode_release; - if (mdev->parent) - mdev->dev.parent = mdev->parent; - dev_set_name(&mdev->dev, "media%d", mdev->minor); - ret = device_register(&mdev->dev); + devnode->dev.bus = &media_bus_type; + devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); + devnode->dev.release = media_devnode_release; + if (devnode->parent) + devnode->dev.parent = devnode->parent; + dev_set_name(&devnode->dev, "media%d", devnode->minor); + ret = device_register(&devnode->dev); if (ret < 0) { pr_err("%s: device_register failed\n", __func__); goto error; } /* Part 4: Activate this minor. The char device can now be used. */ - set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); return 0; error: mutex_lock(&media_devnode_lock); - cdev_del(&mdev->cdev); - clear_bit(mdev->minor, media_devnode_nums); + cdev_del(&devnode->cdev); + clear_bit(devnode->minor, media_devnode_nums); mutex_unlock(&media_devnode_lock); return ret; } -void media_devnode_unregister(struct media_devnode *mdev) +void media_devnode_unregister(struct media_devnode *devnode) { - /* Check if mdev was ever registered at all */ - if (!media_devnode_is_registered(mdev)) + /* Check if devnode was ever registered at all */ + if (!media_devnode_is_registered(devnode)) return; mutex_lock(&media_devnode_lock); - clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); mutex_unlock(&media_devnode_lock); - device_unregister(&mdev->dev); + device_unregister(&devnode->dev); } /* diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index fe42f08e72bd..e1d5af077adb 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -94,7 +94,7 @@ struct media_devnode { unsigned long flags; /* Use bitops to access flags */ /* callbacks */ - void (*release)(struct media_devnode *mdev); + void (*release)(struct media_devnode *devnode); }; /* dev to media_devnode */ @@ -103,7 +103,7 @@ struct media_devnode { /** * media_devnode_register - register a media device node * - * @mdev: media device node structure we want to register + * @devnode: media device node structure we want to register * @owner: should be filled with %THIS_MODULE * * The registration code assigns minor numbers and registers the new device node @@ -116,12 +116,12 @@ struct media_devnode { * the media_devnode structure is *not* called, so the caller is responsible for * freeing any data. */ -int __must_check media_devnode_register(struct media_devnode *mdev, +int __must_check media_devnode_register(struct media_devnode *devnode, struct module *owner); /** * media_devnode_unregister - unregister a media device node - * @mdev: the device node to unregister + * @devnode: the device node to unregister * * This unregisters the passed device. Future open calls will be met with * errors. @@ -129,7 +129,7 @@ int __must_check media_devnode_register(struct media_devnode *mdev, * This function can safely be called if the device node has never been * registered or has already been unregistered. */ -void media_devnode_unregister(struct media_devnode *mdev); +void media_devnode_unregister(struct media_devnode *devnode); /** * media_devnode_data - returns a pointer to the &media_devnode @@ -145,11 +145,11 @@ static inline struct media_devnode *media_devnode_data(struct file *filp) * media_devnode_is_registered - returns true if &media_devnode is registered; * false otherwise. * - * @mdev: pointer to struct &media_devnode. + * @devnode: pointer to struct &media_devnode. */ -static inline int media_devnode_is_registered(struct media_devnode *mdev) +static inline int media_devnode_is_registered(struct media_devnode *devnode) { - return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); } #endif /* _MEDIA_DEVNODE_H */ -- cgit v1.2.3 From a087ce704b802becbb4b0f2a20f2cb3f6911802e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 27 Apr 2016 19:28:26 -0300 Subject: [media] media-device: dynamically allocate struct media_devnode struct media_devnode is currently embedded at struct media_device. While this works fine during normal usage, it leads to a race condition during devnode unregister. the problem is that drivers assume that, after calling media_device_unregister(), the struct that contains media_device can be freed. This is not true, as it can't be freed until userspace closes all opened /dev/media devnodes. In other words, if the media devnode is still open, and media_device gets freed, any call to an ioctl will make the core to try to access struct media_device, with will cause an use-after-free and even GPF. Fix this by dynamically allocating the struct media_devnode and only freeing it when it is safe. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 44 +++++++++++++++++++++++----------- drivers/media/media-devnode.c | 7 +++++- drivers/media/usb/au0828/au0828-core.c | 4 ++-- drivers/media/usb/uvc/uvc_driver.c | 2 +- include/media/media-device.h | 5 +--- include/media/media-devnode.h | 13 +++++++++- 6 files changed, 52 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index a1cd50f331f1..e61fa66d95df 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -423,7 +423,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = to_media_device(devnode); + struct media_device *dev = devnode->media_dev; long ret; mutex_lock(&dev->graph_mutex); @@ -495,7 +495,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = to_media_device(devnode); + struct media_device *dev = devnode->media_dev; long ret; switch (cmd) { @@ -531,7 +531,8 @@ static const struct media_file_operations media_device_fops = { static ssize_t show_model(struct device *cd, struct device_attribute *attr, char *buf) { - struct media_device *mdev = to_media_device(to_media_devnode(cd)); + struct media_devnode *devnode = to_media_devnode(cd); + struct media_device *mdev = devnode->media_dev; return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); } @@ -704,23 +705,34 @@ EXPORT_SYMBOL_GPL(media_device_cleanup); int __must_check __media_device_register(struct media_device *mdev, struct module *owner) { + struct media_devnode *devnode; int ret; + devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); + if (!devnode) + return -ENOMEM; + /* Register the device node. */ - mdev->devnode.fops = &media_device_fops; - mdev->devnode.parent = mdev->dev; - mdev->devnode.release = media_device_release; + mdev->devnode = devnode; + devnode->fops = &media_device_fops; + devnode->parent = mdev->dev; + devnode->release = media_device_release; /* Set version 0 to indicate user-space that the graph is static */ mdev->topology_version = 0; - ret = media_devnode_register(&mdev->devnode, owner); - if (ret < 0) + ret = media_devnode_register(mdev, devnode, owner); + if (ret < 0) { + mdev->devnode = NULL; + kfree(devnode); return ret; + } - ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); + ret = device_create_file(&devnode->dev, &dev_attr_model); if (ret < 0) { - media_devnode_unregister(&mdev->devnode); + mdev->devnode = NULL; + media_devnode_unregister(devnode); + kfree(devnode); return ret; } @@ -771,7 +783,7 @@ void media_device_unregister(struct media_device *mdev) mutex_lock(&mdev->graph_mutex); /* Check if mdev was ever registered at all */ - if (!media_devnode_is_registered(&mdev->devnode)) { + if (!media_devnode_is_registered(mdev->devnode)) { mutex_unlock(&mdev->graph_mutex); return; } @@ -794,9 +806,13 @@ void media_device_unregister(struct media_device *mdev) mutex_unlock(&mdev->graph_mutex); - device_remove_file(&mdev->devnode.dev, &dev_attr_model); - dev_dbg(mdev->dev, "Media device unregistering\n"); - media_devnode_unregister(&mdev->devnode); + dev_dbg(mdev->dev, "Media device unregistered\n"); + + /* Check if mdev devnode was registered */ + if (media_devnode_is_registered(mdev->devnode)) { + device_remove_file(&mdev->devnode->dev, &dev_attr_model); + media_devnode_unregister(mdev->devnode); + } } EXPORT_SYMBOL_GPL(media_device_unregister); diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 7481c9610945..ecdc02d6ed83 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -44,6 +44,7 @@ #include #include +#include #define MEDIA_NUM_DEVICES 256 #define MEDIA_NAME "media" @@ -74,6 +75,8 @@ static void media_devnode_release(struct device *cd) /* Release media_devnode and perform other cleanups as needed. */ if (devnode->release) devnode->release(devnode); + + kfree(devnode); } static struct bus_type media_bus_type = { @@ -219,7 +222,8 @@ static const struct file_operations media_devnode_fops = { .llseek = no_llseek, }; -int __must_check media_devnode_register(struct media_devnode *devnode, +int __must_check media_devnode_register(struct media_device *mdev, + struct media_devnode *devnode, struct module *owner) { int minor; @@ -238,6 +242,7 @@ int __must_check media_devnode_register(struct media_devnode *devnode, mutex_unlock(&media_devnode_lock); devnode->minor = minor; + devnode->media_dev = mdev; /* Part 2: Initialize and register the character device */ cdev_init(&devnode->cdev, &media_devnode_fops); diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 321ea5cf1329..bf53553d2624 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -142,7 +142,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev) struct media_device *mdev = dev->media_dev; struct media_entity_notify *notify, *nextp; - if (!mdev || !media_devnode_is_registered(&mdev->devnode)) + if (!mdev || !media_devnode_is_registered(mdev->devnode)) return; /* Remove au0828 entity_notify callbacks */ @@ -482,7 +482,7 @@ static int au0828_media_device_register(struct au0828_dev *dev, if (!dev->media_dev) return 0; - if (!media_devnode_is_registered(&dev->media_dev->devnode)) { + if (!media_devnode_is_registered(dev->media_dev->devnode)) { /* register media device */ ret = media_device_register(dev->media_dev); diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 451e84e962e2..302e284a95eb 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1674,7 +1674,7 @@ static void uvc_delete(struct uvc_device *dev) if (dev->vdev.dev) v4l2_device_unregister(&dev->vdev); #ifdef CONFIG_MEDIA_CONTROLLER - if (media_devnode_is_registered(&dev->mdev.devnode)) + if (media_devnode_is_registered(dev->mdev.devnode)) media_device_unregister(&dev->mdev); media_device_cleanup(&dev->mdev); #endif diff --git a/include/media/media-device.h b/include/media/media-device.h index a9b33c47310d..f743ae2210ee 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -347,7 +347,7 @@ struct media_entity_notify { struct media_device { /* dev->driver_data points to this struct. */ struct device *dev; - struct media_devnode devnode; + struct media_devnode *devnode; char model[32]; char driver_name[32]; @@ -393,9 +393,6 @@ struct usb_device; #define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0 #define MEDIA_DEV_NOTIFY_POST_LINK_CH 1 -/* media_devnode to media_device */ -#define to_media_device(node) container_of(node, struct media_device, devnode) - /** * media_entity_enum_init - Initialise an entity enumeration * diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index e1d5af077adb..5bb3b0e86d73 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -33,6 +33,8 @@ #include #include +struct media_device; + /* * Flag to mark the media_devnode struct as registered. Drivers must not touch * this flag directly, it will be set and cleared by media_devnode_register and @@ -81,6 +83,8 @@ struct media_file_operations { * before registering the node. */ struct media_devnode { + struct media_device *media_dev; + /* device ops */ const struct media_file_operations *fops; @@ -103,6 +107,7 @@ struct media_devnode { /** * media_devnode_register - register a media device node * + * @media_dev: struct media_device we want to register a device node * @devnode: media device node structure we want to register * @owner: should be filled with %THIS_MODULE * @@ -116,7 +121,8 @@ struct media_devnode { * the media_devnode structure is *not* called, so the caller is responsible for * freeing any data. */ -int __must_check media_devnode_register(struct media_devnode *devnode, +int __must_check media_devnode_register(struct media_device *mdev, + struct media_devnode *devnode, struct module *owner); /** @@ -146,9 +152,14 @@ static inline struct media_devnode *media_devnode_data(struct file *filp) * false otherwise. * * @devnode: pointer to struct &media_devnode. + * + * Note: If mdev is NULL, it also returns false. */ static inline int media_devnode_is_registered(struct media_devnode *devnode) { + if (!devnode) + return false; + return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); } -- cgit v1.2.3 From 6f0dd24a084a17f9984dd49dffbf7055bf123993 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 10 Jun 2016 14:37:23 -0300 Subject: [media] media: fix media devnode ioctl/syscall and unregister race Media devnode open/ioctl could be in progress when media device unregister is initiated. System calls and ioctls check media device registered status at the beginning, however, there is a window where unregister could be in progress without changing the media devnode status to unregistered. process 1 process 2 fd = open(/dev/media0) media_devnode_is_registered() (returns true here) media_device_unregister() (unregister is in progress and devnode isn't unregistered yet) ... ioctl(fd, ...) __media_ioctl() media_devnode_is_registered() (returns true here) ... media_devnode_unregister() ... (driver releases the media device memory) media_device_ioctl() (By this point devnode->media_dev does not point to allocated memory. use-after free in in mutex_lock_nested) BUG: KASAN: use-after-free in mutex_lock_nested+0x79c/0x800 at addr ffff8801ebe914f0 Fix it by clearing register bit when unregister starts to avoid the race. process 1 process 2 fd = open(/dev/media0) media_devnode_is_registered() (could return true here) media_device_unregister() (clear the register bit, then start unregister.) ... ioctl(fd, ...) __media_ioctl() media_devnode_is_registered() (return false here, ioctl returns I/O error, and will not access media device memory) ... media_devnode_unregister() ... (driver releases the media device memory) Signed-off-by: Shuah Khan Suggested-by: Sakari Ailus Reported-by: Mauro Carvalho Chehab Tested-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 15 ++++++++------- drivers/media/media-devnode.c | 8 +++++++- include/media/media-devnode.h | 16 ++++++++++++++-- 3 files changed, 29 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 33a99524216a..1795abeda658 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -732,6 +732,7 @@ int __must_check __media_device_register(struct media_device *mdev, if (ret < 0) { /* devnode free is handled in media_devnode_*() */ mdev->devnode = NULL; + media_devnode_unregister_prepare(devnode); media_devnode_unregister(devnode); return ret; } @@ -788,6 +789,9 @@ void media_device_unregister(struct media_device *mdev) return; } + /* Clear the devnode register bit to avoid races with media dev open */ + media_devnode_unregister_prepare(mdev->devnode); + /* Remove all entities from the media device */ list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) __media_device_unregister_entity(entity); @@ -808,13 +812,10 @@ void media_device_unregister(struct media_device *mdev) dev_dbg(mdev->dev, "Media device unregistered\n"); - /* Check if mdev devnode was registered */ - if (media_devnode_is_registered(mdev->devnode)) { - device_remove_file(&mdev->devnode->dev, &dev_attr_model); - media_devnode_unregister(mdev->devnode); - /* devnode free is handled in media_devnode_*() */ - mdev->devnode = NULL; - } + device_remove_file(&mdev->devnode->dev, &dev_attr_model); + media_devnode_unregister(mdev->devnode); + /* devnode free is handled in media_devnode_*() */ + mdev->devnode = NULL; } EXPORT_SYMBOL_GPL(media_device_unregister); diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 5b605ff38daf..f2772ba6f611 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -287,7 +287,7 @@ cdev_add_error: return ret; } -void media_devnode_unregister(struct media_devnode *devnode) +void media_devnode_unregister_prepare(struct media_devnode *devnode) { /* Check if devnode was ever registered at all */ if (!media_devnode_is_registered(devnode)) @@ -295,6 +295,12 @@ void media_devnode_unregister(struct media_devnode *devnode) mutex_lock(&media_devnode_lock); clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); + mutex_unlock(&media_devnode_lock); +} + +void media_devnode_unregister(struct media_devnode *devnode) +{ + mutex_lock(&media_devnode_lock); /* Delete the cdev on this minor as well */ cdev_del(&devnode->cdev); mutex_unlock(&media_devnode_lock); diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index 5bb3b0e86d73..f0b7dd79fb92 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -125,6 +125,19 @@ int __must_check media_devnode_register(struct media_device *mdev, struct media_devnode *devnode, struct module *owner); +/** + * media_devnode_unregister_prepare - clear the media device node register bit + * @devnode: the device node to prepare for unregister + * + * This clears the passed device register bit. Future open calls will be met + * with errors. Should be called before media_devnode_unregister() to avoid + * races with unregister and device file open calls. + * + * This function can safely be called if the device node has never been + * registered or has already been unregistered. + */ +void media_devnode_unregister_prepare(struct media_devnode *devnode); + /** * media_devnode_unregister - unregister a media device node * @devnode: the device node to unregister @@ -132,8 +145,7 @@ int __must_check media_devnode_register(struct media_device *mdev, * This unregisters the passed device. Future open calls will be met with * errors. * - * This function can safely be called if the device node has never been - * registered or has already been unregistered. + * Should be called after media_devnode_unregister_prepare() */ void media_devnode_unregister(struct media_devnode *devnode); -- cgit v1.2.3 From 0db5c79989de2c68d5abb7ba891bfdb3cd3b7e05 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 16 Jun 2016 08:04:40 -0300 Subject: [media] media-devnode.h: Fix documentation Two parameters were documented with a wrong name, and a struct device pointer description was missing. That caused the following warnings, when building documentation: include/media/media-devnode.h:102: warning: No description found for parameter 'media_dev' include/media/media-devnode.h:126: warning: No description found for parameter 'mdev' include/media/media-devnode.h:126: warning: Excess function parameter 'media_dev' description in 'media_devnode_register' Rename the description, to match the function parameter and fix Documentation. No funcional changes. Signed-off-by: Mauro Carvalho Chehab --- include/media/media-devnode.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index f0b7dd79fb92..37d494805944 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -69,8 +69,9 @@ struct media_file_operations { /** * struct media_devnode - Media device node + * @media_dev: pointer to struct &media_device * @fops: pointer to struct &media_file_operations with media device ops - * @dev: struct device pointer for the media controller device + * @dev: pointer to struct &device containing the media controller device * @cdev: struct cdev pointer character device * @parent: parent device * @minor: device node minor number @@ -107,7 +108,7 @@ struct media_devnode { /** * media_devnode_register - register a media device node * - * @media_dev: struct media_device we want to register a device node + * @mdev: struct media_device we want to register a device node * @devnode: media device node structure we want to register * @owner: should be filled with %THIS_MODULE * -- cgit v1.2.3 From 7b49235e83b2347caf4bc66dd0154cb799bd7405 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 11 Feb 2016 22:29:58 -0200 Subject: [media] v4l: Add Renesas R-Car FCP driver The FCP is a companion module of video processing modules in the Renesas R-Car Gen3 SoCs. It provides data compression and decompression, data caching, and conversion of AXI transactions in order to reduce the memory bandwidth. The driver is not meant to be used standalone but provides an API to the video processing modules to control the FCP. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 10 +++ drivers/media/platform/Kconfig | 13 +++ drivers/media/platform/Makefile | 1 + drivers/media/platform/rcar-fcp.c | 181 ++++++++++++++++++++++++++++++++++++++ include/media/rcar-fcp.h | 37 ++++++++ 5 files changed, 242 insertions(+) create mode 100644 drivers/media/platform/rcar-fcp.c create mode 100644 include/media/rcar-fcp.h (limited to 'include') diff --git a/MAINTAINERS b/MAINTAINERS index 02299fd2db18..949a920ca198 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7312,6 +7312,16 @@ L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/potentiometer/mcp4531.c +MEDIA DRIVERS FOR RENESAS - FCP +M: Laurent Pinchart +L: linux-media@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Supported +F: Documentation/devicetree/bindings/media/renesas,fcp.txt +F: drivers/media/platform/rcar-fcp.c +F: include/media/rcar-fcp.h + MEDIA DRIVERS FOR RENESAS - VSP1 M: Laurent Pinchart L: linux-media@vger.kernel.org diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 382f3937379e..d6fe4fe924e7 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -248,6 +248,19 @@ config VIDEO_RENESAS_JPU To compile this driver as a module, choose M here: the module will be called rcar_jpu. +config VIDEO_RENESAS_FCP + tristate "Renesas Frame Compression Processor" + depends on ARCH_RENESAS || COMPILE_TEST + depends on OF + ---help--- + This is a driver for the Renesas Frame Compression Processor (FCP). + The FCP is a companion module of video processing modules in the + Renesas R-Car Gen3 SoCs. It handles memory access for the codec, + VSP and FDP modules. + + To compile this driver as a module, choose M here: the module + will be called rcar-fcp. + config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 99cf31542f54..c83800a74a2d 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o obj-$(CONFIG_SOC_CAMERA) += soc_camera/ +obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c new file mode 100644 index 000000000000..6a7bcc3028b1 --- /dev/null +++ b/drivers/media/platform/rcar-fcp.c @@ -0,0 +1,181 @@ +/* + * rcar-fcp.c -- R-Car Frame Compression Processor Driver + * + * Copyright (C) 2016 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct rcar_fcp_device { + struct list_head list; + struct device *dev; +}; + +static LIST_HEAD(fcp_devices); +static DEFINE_MUTEX(fcp_lock); + +/* ----------------------------------------------------------------------------- + * Public API + */ + +/** + * rcar_fcp_get - Find and acquire a reference to an FCP instance + * @np: Device node of the FCP instance + * + * Search the list of registered FCP instances for the instance corresponding to + * the given device node. + * + * Return a pointer to the FCP instance, or an ERR_PTR if the instance can't be + * found. + */ +struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np) +{ + struct rcar_fcp_device *fcp; + + mutex_lock(&fcp_lock); + + list_for_each_entry(fcp, &fcp_devices, list) { + if (fcp->dev->of_node != np) + continue; + + /* + * Make sure the module won't be unloaded behind our back. This + * is a poor man's safety net, the module should really not be + * unloaded while FCP users can be active. + */ + if (!try_module_get(fcp->dev->driver->owner)) + fcp = NULL; + + goto done; + } + + fcp = ERR_PTR(-EPROBE_DEFER); + +done: + mutex_unlock(&fcp_lock); + return fcp; +} +EXPORT_SYMBOL_GPL(rcar_fcp_get); + +/** + * rcar_fcp_put - Release a reference to an FCP instance + * @fcp: The FCP instance + * + * Release the FCP instance acquired by a call to rcar_fcp_get(). + */ +void rcar_fcp_put(struct rcar_fcp_device *fcp) +{ + if (fcp) + module_put(fcp->dev->driver->owner); +} +EXPORT_SYMBOL_GPL(rcar_fcp_put); + +/** + * rcar_fcp_enable - Enable an FCP + * @fcp: The FCP instance + * + * Before any memory access through an FCP is performed by a module, the FCP + * must be enabled by a call to this function. The enable calls are reference + * counted, each successful call must be followed by one rcar_fcp_disable() + * call when no more memory transfer can occur through the FCP. + * + * Return 0 on success or a negative error code if an error occurs. The enable + * reference count isn't increased when this function returns an error. + */ +int rcar_fcp_enable(struct rcar_fcp_device *fcp) +{ + if (!fcp) + return 0; + + return pm_runtime_get_sync(fcp->dev); +} +EXPORT_SYMBOL_GPL(rcar_fcp_enable); + +/** + * rcar_fcp_disable - Disable an FCP + * @fcp: The FCP instance + * + * This function is the counterpart of rcar_fcp_enable(). As enable calls are + * reference counted a disable call may not disable the FCP synchronously. + */ +void rcar_fcp_disable(struct rcar_fcp_device *fcp) +{ + if (fcp) + pm_runtime_put(fcp->dev); +} +EXPORT_SYMBOL_GPL(rcar_fcp_disable); + +/* ----------------------------------------------------------------------------- + * Platform Driver + */ + +static int rcar_fcp_probe(struct platform_device *pdev) +{ + struct rcar_fcp_device *fcp; + + fcp = devm_kzalloc(&pdev->dev, sizeof(*fcp), GFP_KERNEL); + if (fcp == NULL) + return -ENOMEM; + + fcp->dev = &pdev->dev; + + pm_runtime_enable(&pdev->dev); + + mutex_lock(&fcp_lock); + list_add_tail(&fcp->list, &fcp_devices); + mutex_unlock(&fcp_lock); + + platform_set_drvdata(pdev, fcp); + + return 0; +} + +static int rcar_fcp_remove(struct platform_device *pdev) +{ + struct rcar_fcp_device *fcp = platform_get_drvdata(pdev); + + mutex_lock(&fcp_lock); + list_del(&fcp->list); + mutex_unlock(&fcp_lock); + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id rcar_fcp_of_match[] = { + { .compatible = "renesas,fcpv" }, + { }, +}; + +static struct platform_driver rcar_fcp_platform_driver = { + .probe = rcar_fcp_probe, + .remove = rcar_fcp_remove, + .driver = { + .name = "rcar-fcp", + .of_match_table = rcar_fcp_of_match, + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(rcar_fcp_platform_driver); + +MODULE_ALIAS("rcar-fcp"); +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("Renesas FCP Driver"); +MODULE_LICENSE("GPL"); diff --git a/include/media/rcar-fcp.h b/include/media/rcar-fcp.h new file mode 100644 index 000000000000..4c7fc77eaf29 --- /dev/null +++ b/include/media/rcar-fcp.h @@ -0,0 +1,37 @@ +/* + * rcar-fcp.h -- R-Car Frame Compression Processor Driver + * + * Copyright (C) 2016 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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. + */ +#ifndef __MEDIA_RCAR_FCP_H__ +#define __MEDIA_RCAR_FCP_H__ + +struct device_node; +struct rcar_fcp_device; + +#if IS_ENABLED(CONFIG_VIDEO_RENESAS_FCP) +struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np); +void rcar_fcp_put(struct rcar_fcp_device *fcp); +int rcar_fcp_enable(struct rcar_fcp_device *fcp); +void rcar_fcp_disable(struct rcar_fcp_device *fcp); +#else +static inline struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np) +{ + return ERR_PTR(-ENOENT); +} +static inline void rcar_fcp_put(struct rcar_fcp_device *fcp) { } +static inline int rcar_fcp_enable(struct rcar_fcp_device *fcp) +{ + return -ENOSYS; +} +static inline void rcar_fcp_disable(struct rcar_fcp_device *fcp) { } +#endif + +#endif /* __MEDIA_RCAR_FCP_H__ */ -- cgit v1.2.3 From c6b013ab517b0ae09036d50f6b1684d9dbedf596 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Apr 2016 19:08:59 -0300 Subject: [media] v4l: vsp1: Group DRM RPF parameters in a structure The vsp1_du_atomic_update_ext() function takes 7 RPF configuration parameters, and more will likely be added later. This makes the code difficult to read and error-prone as multiple parameters have the same type. Make the API safer and easier to extend in the future by grouping all parameters in a structure. Use macro magic to ease the transition to the new function by allowing the old and new functions to be called using the same name. The macros and static inline wrapper will be removed as soon as the caller is updated. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drm.c | 68 +++++++++++++++------------------- include/media/vsp1.h | 47 ++++++++++++++++------- 2 files changed, 64 insertions(+), 51 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index fc4bbc401e67..fef53ecefe25 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -230,42 +230,33 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline * @dev: the VSP device * @rpf_index: index of the RPF to setup (0-based) - * @pixelformat: V4L2 pixel format for the RPF memory input - * @pitch: number of bytes per line in the image stored in memory - * @mem: DMA addresses of the memory buffers (one per plane) - * @src: the source crop rectangle for the RPF - * @dst: the destination compose rectangle for the BRU input - * @alpha: global alpha value for the input - * @zpos: the Z-order position of the input + * @cfg: the RPF configuration * - * Configure the VSP to perform composition of the image referenced by @mem - * through RPF @rpf_index, using the @src crop rectangle and the @dst + * Configure the VSP to perform image composition through RPF @rpf_index as + * described by the @cfg configuration. The image to compose is referenced by + * @cfg.mem and composed using the @cfg.src crop rectangle and the @cfg.dst * composition rectangle. The Z-order is configurable with higher @zpos values * displayed on top. * - * Image format as stored in memory is expressed as a V4L2 @pixelformat value. - * As a special case, setting the pixel format to 0 will disable the RPF. The - * @pitch, @mem, @src and @dst parameters are ignored in that case. Calling the + * If the @cfg configuration is NULL, the RPF will be disabled. Calling the * function on a disabled RPF is allowed. * - * The memory pitch is configurable to allow for padding at end of lines, or - * simple for images that extend beyond the crop rectangle boundaries. The - * @pitch value is expressed in bytes and applies to all planes for multiplanar - * formats. + * Image format as stored in memory is expressed as a V4L2 @cfg.pixelformat + * value. The memory pitch is configurable to allow for padding at end of lines, + * or simply for images that extend beyond the crop rectangle boundaries. The + * @cfg.pitch value is expressed in bytes and applies to all planes for + * multiplanar formats. * * The source memory buffer is referenced by the DMA address of its planes in - * the @mem array. Up to two planes are supported. The second plane DMA address - * is ignored for formats using a single plane. + * the @cfg.mem array. Up to two planes are supported. The second plane DMA + * address is ignored for formats using a single plane. * * This function isn't reentrant, the caller needs to serialize calls. * * Return 0 on success or a negative error code on failure. */ -int vsp1_du_atomic_update_ext(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, unsigned int alpha, - unsigned int zpos) +int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, + const struct vsp1_du_atomic_config *cfg) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); const struct vsp1_format_info *fmtinfo; @@ -276,7 +267,7 @@ int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, rpf = vsp1->rpf[rpf_index]; - if (pixelformat == 0) { + if (!cfg) { dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__, rpf_index); @@ -287,38 +278,39 @@ int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, dev_dbg(vsp1->dev, "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n", __func__, rpf_index, - src->left, src->top, src->width, src->height, - dst->left, dst->top, dst->width, dst->height, - pixelformat, pitch, &mem[0], &mem[1], zpos); + cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height, + cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height, + cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1], + cfg->zpos); /* Store the format, stride, memory buffer address, crop and compose * rectangles and Z-order position and for the input. */ - fmtinfo = vsp1_get_format_info(pixelformat); + fmtinfo = vsp1_get_format_info(cfg->pixelformat); if (!fmtinfo) { dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", - pixelformat); + cfg->pixelformat); return -EINVAL; } rpf->fmtinfo = fmtinfo; rpf->format.num_planes = fmtinfo->planes; - rpf->format.plane_fmt[0].bytesperline = pitch; - rpf->format.plane_fmt[1].bytesperline = pitch; - rpf->alpha = alpha; + rpf->format.plane_fmt[0].bytesperline = cfg->pitch; + rpf->format.plane_fmt[1].bytesperline = cfg->pitch; + rpf->alpha = cfg->alpha; - rpf->mem.addr[0] = mem[0]; - rpf->mem.addr[1] = mem[1]; + rpf->mem.addr[0] = cfg->mem[0]; + rpf->mem.addr[1] = cfg->mem[1]; rpf->mem.addr[2] = 0; - vsp1->drm->inputs[rpf_index].crop = *src; - vsp1->drm->inputs[rpf_index].compose = *dst; - vsp1->drm->inputs[rpf_index].zpos = zpos; + vsp1->drm->inputs[rpf_index].crop = cfg->src; + vsp1->drm->inputs[rpf_index].compose = cfg->dst; + vsp1->drm->inputs[rpf_index].zpos = cfg->zpos; vsp1->drm->inputs[rpf_index].enabled = true; return 0; } -EXPORT_SYMBOL_GPL(vsp1_du_atomic_update_ext); +EXPORT_SYMBOL_GPL(__vsp1_du_atomic_update); static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf, unsigned int bru_input) diff --git a/include/media/vsp1.h b/include/media/vsp1.h index 3e654a0455bd..ea8ad7537057 100644 --- a/include/media/vsp1.h +++ b/include/media/vsp1.h @@ -14,31 +14,52 @@ #define __MEDIA_VSP1_H__ #include +#include struct device; -struct v4l2_rect; int vsp1_du_init(struct device *dev); int vsp1_du_setup_lif(struct device *dev, unsigned int width, unsigned int height); +struct vsp1_du_atomic_config { + u32 pixelformat; + unsigned int pitch; + dma_addr_t mem[2]; + struct v4l2_rect src; + struct v4l2_rect dst; + unsigned int alpha; + unsigned int zpos; +}; + 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); +int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf, + const struct vsp1_du_atomic_config *cfg); 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) +static inline int vsp1_du_atomic_update_old(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) { - return vsp1_du_atomic_update_ext(dev, rpf_index, pixelformat, pitch, - mem, src, dst, 255, 0); + struct vsp1_du_atomic_config cfg = { + .pixelformat = pixelformat, + .pitch = pitch, + .mem[0] = mem[0], + .mem[1] = mem[1], + .src = *src, + .dst = *dst, + .alpha = 255, + .zpos = 0, + }; + + return __vsp1_du_atomic_update(dev, rpf, &cfg); } +#define _vsp1_du_atomic_update(_1, _2, _3, _4, _5, _6, _7, f, ...) f +#define vsp1_du_atomic_update(...) \ + _vsp1_du_atomic_update(__VA_ARGS__, vsp1_du_atomic_update_old, 0, 0, \ + 0, __vsp1_du_atomic_update)(__VA_ARGS__) + #endif /* __MEDIA_VSP1_H__ */ -- cgit v1.2.3 From c3f34a4bdd596127000666c17bbf8ba1c3d2d332 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 23 Apr 2016 20:11:59 -0300 Subject: [media] v4l: vsp1: Remove deprecated DRM API The DRM driver has switched to the new API, remove the deprecated macros and inline wrapper. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drm.c | 6 +++--- include/media/vsp1.h | 28 ++-------------------------- 2 files changed, 5 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index fef53ecefe25..14730119687f 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -255,8 +255,8 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); * * Return 0 on success or a negative error code on failure. */ -int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, - const struct vsp1_du_atomic_config *cfg) +int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, + const struct vsp1_du_atomic_config *cfg) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); const struct vsp1_format_info *fmtinfo; @@ -310,7 +310,7 @@ int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, return 0; } -EXPORT_SYMBOL_GPL(__vsp1_du_atomic_update); +EXPORT_SYMBOL_GPL(vsp1_du_atomic_update); static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf, unsigned int bru_input) diff --git a/include/media/vsp1.h b/include/media/vsp1.h index ea8ad7537057..9322d9775fb7 100644 --- a/include/media/vsp1.h +++ b/include/media/vsp1.h @@ -34,32 +34,8 @@ struct vsp1_du_atomic_config { }; void vsp1_du_atomic_begin(struct device *dev); -int __vsp1_du_atomic_update(struct device *dev, unsigned int rpf, - const struct vsp1_du_atomic_config *cfg); +int vsp1_du_atomic_update(struct device *dev, unsigned int rpf, + const struct vsp1_du_atomic_config *cfg); void vsp1_du_atomic_flush(struct device *dev); -static inline int vsp1_du_atomic_update_old(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) -{ - struct vsp1_du_atomic_config cfg = { - .pixelformat = pixelformat, - .pitch = pitch, - .mem[0] = mem[0], - .mem[1] = mem[1], - .src = *src, - .dst = *dst, - .alpha = 255, - .zpos = 0, - }; - - return __vsp1_du_atomic_update(dev, rpf, &cfg); -} - -#define _vsp1_du_atomic_update(_1, _2, _3, _4, _5, _6, _7, f, ...) f -#define vsp1_du_atomic_update(...) \ - _vsp1_du_atomic_update(__VA_ARGS__, vsp1_du_atomic_update_old, 0, 0, \ - 0, __vsp1_du_atomic_update)(__VA_ARGS__) - #endif /* __MEDIA_VSP1_H__ */ -- cgit v1.2.3 From ff42c8aa6c5d05b7e084c81c1d02554839d7e9e1 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Mon, 17 Aug 2015 08:47:41 -0300 Subject: [media] rc: Add HDMI CEC protocol handling Add handling of remote control events coming from the HDMI CEC bus and the new protocol required for that. Signed-off-by: Kamil Debski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 1 + include/media/rc-map.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 7dfc7c2188f0..c717eafd9d22 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -804,6 +804,7 @@ static const struct { { RC_BIT_SHARP, "sharp", "ir-sharp-decoder" }, { RC_BIT_MCE_KBD, "mce_kbd", "ir-mce_kbd-decoder" }, { RC_BIT_XMP, "xmp", "ir-xmp-decoder" }, + { RC_BIT_CEC, "cec", NULL }, }; /** diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 7844e9879497..6e6557dbeb9f 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -31,6 +31,7 @@ enum rc_type { RC_TYPE_RC6_MCE = 16, /* MCE (Philips RC6-6A-32 subtype) protocol */ RC_TYPE_SHARP = 17, /* Sharp protocol */ RC_TYPE_XMP = 18, /* XMP protocol */ + RC_TYPE_CEC = 19, /* CEC protocol */ }; #define RC_BIT_NONE 0ULL @@ -53,6 +54,7 @@ enum rc_type { #define RC_BIT_RC6_MCE (1ULL << RC_TYPE_RC6_MCE) #define RC_BIT_SHARP (1ULL << RC_TYPE_SHARP) #define RC_BIT_XMP (1ULL << RC_TYPE_XMP) +#define RC_BIT_CEC (1ULL << RC_TYPE_CEC) #define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | \ RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \ @@ -61,7 +63,7 @@ enum rc_type { RC_BIT_NEC | RC_BIT_SANYO | RC_BIT_MCE_KBD | \ RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \ RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \ - RC_BIT_XMP) + RC_BIT_XMP | RC_BIT_CEC) #define RC_SCANCODE_UNKNOWN(x) (x) @@ -123,6 +125,7 @@ void rc_map_init(void); #define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" #define RC_MAP_BEHOLD "rc-behold" #define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old" +#define RC_MAP_CEC "rc-cec" #define RC_MAP_CINERGY_1400 "rc-cinergy-1400" #define RC_MAP_CINERGY "rc-cinergy" #define RC_MAP_DELOCK_61959 "rc-delock-61959" -- cgit v1.2.3 From 904aef0f9f6deff94223c0ce93eb598c47dd3aad Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 15 Jun 2016 09:57:48 -0300 Subject: [media] v4l2-ctrl.h: fix comments The comments for the unlocked v4l2_ctrl_s_ctrl* functions were wrong (copy and pasted from the locked variants). Fix this, since it is confusing. Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 0bc9b35b8f3e..5c2ed0cfb841 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -759,9 +759,9 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl); * @ctrl: The control. * @val: The new value. * - * This set the control's new value safely by going through the control - * framework. This function will lock the control's handler, so it cannot be - * used from within the &v4l2_ctrl_ops functions. + * This sets the control's new value safely by going through the control + * framework. This function assumes the control's handler is already locked, + * allowing it to be used from within the &v4l2_ctrl_ops functions. * * This function is for integer type controls only. */ @@ -771,7 +771,7 @@ int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val); * @ctrl: The control. * @val: The new value. * - * This set the control's new value safely by going through the control + * This sets the control's new value safely by going through the control * framework. This function will lock the control's handler, so it cannot be * used from within the &v4l2_ctrl_ops functions. * @@ -807,9 +807,9 @@ s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl); * @ctrl: The control. * @val: The new value. * - * This set the control's new value safely by going through the control - * framework. This function will lock the control's handler, so it cannot be - * used from within the &v4l2_ctrl_ops functions. + * This sets the control's new value safely by going through the control + * framework. This function assumes the control's handler is already locked, + * allowing it to be used from within the &v4l2_ctrl_ops functions. * * This function is for 64-bit integer type controls only. */ @@ -821,7 +821,7 @@ int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val); * @ctrl: The control. * @val: The new value. * - * This set the control's new value safely by going through the control + * This sets the control's new value safely by going through the control * framework. This function will lock the control's handler, so it cannot be * used from within the &v4l2_ctrl_ops functions. * @@ -843,9 +843,9 @@ static inline int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val) * @ctrl: The control. * @s: The new string. * - * This set the control's new string safely by going through the control - * framework. This function will lock the control's handler, so it cannot be - * used from within the &v4l2_ctrl_ops functions. + * This sets the control's new string safely by going through the control + * framework. This function assumes the control's handler is already locked, + * allowing it to be used from within the &v4l2_ctrl_ops functions. * * This function is for string type controls only. */ @@ -857,7 +857,7 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s); * @ctrl: The control. * @s: The new string. * - * This set the control's new string safely by going through the control + * This sets the control's new string safely by going through the control * framework. This function will lock the control's handler, so it cannot be * used from within the &v4l2_ctrl_ops functions. * -- cgit v1.2.3 From 29fb44a58ac12bffe4c225f95afdc22364db070e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jun 2016 09:13:08 -0300 Subject: [media] cec-edid: add module for EDID CEC helper functions The cec-edid module contains helper functions to find and manipulate the CEC physical address inside an EDID. Even if the CEC support itself is disabled, drivers will still need these functions. Which is the reason this is module is separate from the upcoming CEC framework. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 3 + drivers/media/Makefile | 2 + drivers/media/cec-edid.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++ include/media/cec-edid.h | 104 +++++++++++++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 drivers/media/cec-edid.c create mode 100644 include/media/cec-edid.h (limited to 'include') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index a8518fb3bca7..052dcf77174b 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -80,6 +80,9 @@ config MEDIA_RC_SUPPORT Say Y when you have a TV or an IR device. +config MEDIA_CEC_EDID + tristate + # # Media controller # Selectable only for webcam/grabbers, as other drivers don't use it diff --git a/drivers/media/Makefile b/drivers/media/Makefile index e608bbce0c35..b56f013b78c3 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,6 +2,8 @@ # Makefile for the kernel multimedia device drivers. # +obj-$(CONFIG_MEDIA_CEC_EDID) += cec-edid.o + media-objs := media-device.o media-devnode.o media-entity.o # diff --git a/drivers/media/cec-edid.c b/drivers/media/cec-edid.c new file mode 100644 index 000000000000..70018247bdda --- /dev/null +++ b/drivers/media/cec-edid.c @@ -0,0 +1,168 @@ +/* + * cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions + * + * Copyright 2016 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. + */ + +#include +#include +#include +#include + +/* + * This EDID is expected to be a CEA-861 compliant, which means that there are + * at least two blocks and one or more of the extensions blocks are CEA-861 + * blocks. + * + * The returned location is guaranteed to be < size - 1. + */ +static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size) +{ + unsigned int blocks = size / 128; + unsigned int block; + u8 d; + + /* Sanity check: at least 2 blocks and a multiple of the block size */ + if (blocks < 2 || size % 128) + return 0; + + /* + * If there are fewer extension blocks than the size, then update + * 'blocks'. It is allowed to have more extension blocks than the size, + * since some hardware can only read e.g. 256 bytes of the EDID, even + * though more blocks are present. The first CEA-861 extension block + * should normally be in block 1 anyway. + */ + if (edid[0x7e] + 1 < blocks) + blocks = edid[0x7e] + 1; + + for (block = 1; block < blocks; block++) { + unsigned int offset = block * 128; + + /* Skip any non-CEA-861 extension blocks */ + if (edid[offset] != 0x02 || edid[offset + 1] != 0x03) + continue; + + /* search Vendor Specific Data Block (tag 3) */ + d = edid[offset + 2] & 0x7f; + /* Check if there are Data Blocks */ + if (d <= 4) + continue; + if (d > 4) { + unsigned int i = offset + 4; + unsigned int end = offset + d; + + /* Note: 'end' is always < 'size' */ + do { + u8 tag = edid[i] >> 5; + u8 len = edid[i] & 0x1f; + + if (tag == 3 && len >= 5 && i + len <= end) + return i + 4; + i += len + 1; + } while (i < end); + } + } + return 0; +} + +u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, + unsigned int *offset) +{ + unsigned int loc = cec_get_edid_spa_location(edid, size); + + if (offset) + *offset = loc; + if (loc == 0) + return CEC_PHYS_ADDR_INVALID; + return (edid[loc] << 8) | edid[loc + 1]; +} +EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr); + +void cec_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr) +{ + unsigned int loc = cec_get_edid_spa_location(edid, size); + u8 sum = 0; + unsigned int i; + + if (loc == 0) + return; + edid[loc] = phys_addr >> 8; + edid[loc + 1] = phys_addr & 0xff; + loc &= ~0x7f; + + /* update the checksum */ + for (i = loc; i < loc + 127; i++) + sum += edid[i]; + edid[i] = 256 - sum; +} +EXPORT_SYMBOL_GPL(cec_set_edid_phys_addr); + +u16 cec_phys_addr_for_input(u16 phys_addr, u8 input) +{ + /* Check if input is sane */ + if (WARN_ON(input == 0 || input > 0xf)) + return CEC_PHYS_ADDR_INVALID; + + if (phys_addr == 0) + return input << 12; + + if ((phys_addr & 0x0fff) == 0) + return phys_addr | (input << 8); + + if ((phys_addr & 0x00ff) == 0) + return phys_addr | (input << 4); + + if ((phys_addr & 0x000f) == 0) + return phys_addr | input; + + /* + * All nibbles are used so no valid physical addresses can be assigned + * to the input. + */ + return CEC_PHYS_ADDR_INVALID; +} +EXPORT_SYMBOL_GPL(cec_phys_addr_for_input); + +int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port) +{ + int i; + + if (parent) + *parent = phys_addr; + if (port) + *port = 0; + if (phys_addr == CEC_PHYS_ADDR_INVALID) + return 0; + for (i = 0; i < 16; i += 4) + if (phys_addr & (0xf << i)) + break; + if (i == 16) + return 0; + if (parent) + *parent = phys_addr & (0xfff0 << i); + if (port) + *port = (phys_addr >> i) & 0xf; + for (i += 4; i < 16; i += 4) + if ((phys_addr & (0xf << i)) == 0) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(cec_phys_addr_validate); + +MODULE_AUTHOR("Hans Verkuil "); +MODULE_DESCRIPTION("CEC EDID helper functions"); +MODULE_LICENSE("GPL"); diff --git a/include/media/cec-edid.h b/include/media/cec-edid.h new file mode 100644 index 000000000000..bdf731ecba1a --- /dev/null +++ b/include/media/cec-edid.h @@ -0,0 +1,104 @@ +/* + * cec-edid - HDMI Consumer Electronics Control & EDID helpers + * + * Copyright 2016 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 _MEDIA_CEC_EDID_H +#define _MEDIA_CEC_EDID_H + +#include + +#define CEC_PHYS_ADDR_INVALID 0xffff +#define cec_phys_addr_exp(pa) \ + ((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf + +/** + * cec_get_edid_phys_addr() - find and return the physical address + * + * @edid: pointer to the EDID data + * @size: size in bytes of the EDID data + * @offset: If not %NULL then the location of the physical address + * bytes in the EDID will be returned here. This is set to 0 + * if there is no physical address found. + * + * Return: the physical address or CEC_PHYS_ADDR_INVALID if there is none. + */ +u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, + unsigned int *offset); + +/** + * cec_set_edid_phys_addr() - find and set the physical address + * + * @edid: pointer to the EDID data + * @size: size in bytes of the EDID data + * @phys_addr: the new physical address + * + * This function finds the location of the physical address in the EDID + * and fills in the given physical address and updates the checksum + * at the end of the EDID block. It does nothing if the EDID doesn't + * contain a physical address. + */ +void cec_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr); + +/** + * cec_phys_addr_for_input() - calculate the PA for an input + * + * @phys_addr: the physical address of the parent + * @input: the number of the input port, must be between 1 and 15 + * + * This function calculates a new physical address based on the input + * port number. For example: + * + * PA = 0.0.0.0 and input = 2 becomes 2.0.0.0 + * + * PA = 3.0.0.0 and input = 1 becomes 3.1.0.0 + * + * PA = 3.2.1.0 and input = 5 becomes 3.2.1.5 + * + * PA = 3.2.1.3 and input = 5 becomes f.f.f.f since it maxed out the depth. + * + * Return: the new physical address or CEC_PHYS_ADDR_INVALID. + */ +u16 cec_phys_addr_for_input(u16 phys_addr, u8 input); + +/** + * cec_phys_addr_validate() - validate a physical address from an EDID + * + * @phys_addr: the physical address to validate + * @parent: if not %NULL, then this is filled with the parents PA. + * @port: if not %NULL, then this is filled with the input port. + * + * This validates a physical address as read from an EDID. If the + * PA is invalid (such as 1.0.1.0 since '0' is only allowed at the end), + * then it will return -EINVAL. + * + * The parent PA is passed into %parent and the input port is passed into + * %port. For example: + * + * PA = 0.0.0.0: has parent 0.0.0.0 and input port 0. + * + * PA = 1.0.0.0: has parent 0.0.0.0 and input port 1. + * + * PA = 3.2.0.0: has parent 3.0.0.0 and input port 2. + * + * PA = f.f.f.f: has parent f.f.f.f and input port 0. + * + * Return: 0 if the PA is valid, -EINVAL if not. + */ +int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port); + +#endif /* _MEDIA_CEC_EDID_H */ -- cgit v1.2.3 From 3132583e5bd7cb56dffb2c04128ec4db12c32027 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jun 2016 09:17:57 -0300 Subject: [media] cec.h: add cec header This header contains the CEC public API. Since the CEC framework will initially be part of staging this header is kept out of include/uapi for the time being until the CEC framework will be moved out of staging. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec.h | 993 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 993 insertions(+) create mode 100644 include/linux/cec.h (limited to 'include') diff --git a/include/linux/cec.h b/include/linux/cec.h new file mode 100644 index 000000000000..40924e79465d --- /dev/null +++ b/include/linux/cec.h @@ -0,0 +1,993 @@ +/* + * cec - HDMI Consumer Electronics Control public header + * + * Copyright 2016 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. + */ + +/* + * Note: this framework is still in staging and it is likely the API + * will change before it goes out of staging. + * + * Once it is moved out of staging this header will move to uapi. + */ +#ifndef _CEC_UAPI_H +#define _CEC_UAPI_H + +#include + +#define CEC_MAX_MSG_SIZE 16 + +/** + * struct cec_msg - CEC message structure. + * @ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the + * driver. It is set when the message transmission has finished + * and it is set when a message was received. + * @len: Length in bytes of the message. + * @timeout: The timeout (in ms) that is used to timeout CEC_RECEIVE. + * Set to 0 if you want to wait forever. This timeout can also be + * used with CEC_TRANSMIT as the timeout for waiting for a reply. + * If 0, then it will use a 1 second timeout instead of waiting + * forever as is done with CEC_RECEIVE. + * @sequence: The framework assigns a sequence number to messages that are + * sent. This can be used to track replies to previously sent + * messages. + * @flags: Set to 0. + * @rx_status: The message receive status bits. Set by the driver. + * @tx_status: The message transmit status bits. Set by the driver. + * @msg: The message payload. + * @reply: This field is ignored with CEC_RECEIVE and is only used by + * CEC_TRANSMIT. If non-zero, then wait for a reply with this + * opcode. Set to CEC_MSG_FEATURE_ABORT if you want to wait for + * a possible ABORT reply. If there was an error when sending the + * msg or FeatureAbort was returned, then reply is set to 0. + * If reply is non-zero upon return, then len/msg are set to + * the received message. + * If reply is zero upon return and status has the + * CEC_TX_STATUS_FEATURE_ABORT bit set, then len/msg are set to + * the received feature abort message. + * If reply is zero upon return and status has the + * CEC_TX_STATUS_MAX_RETRIES bit set, then no reply was seen at + * all. If reply is non-zero for CEC_TRANSMIT and the message is a + * broadcast, then -EINVAL is returned. + * if reply is non-zero, then timeout is set to 1000 (the required + * maximum response time). + * @tx_arb_lost_cnt: The number of 'Arbitration Lost' events. Set by the driver. + * @tx_nack_cnt: The number of 'Not Acknowledged' events. Set by the driver. + * @tx_low_drive_cnt: The number of 'Low Drive Detected' events. Set by the + * driver. + * @tx_error_cnt: The number of 'Error' events. Set by the driver. + */ +struct cec_msg { + __u64 ts; + __u32 len; + __u32 timeout; + __u32 sequence; + __u32 flags; + __u8 rx_status; + __u8 tx_status; + __u8 msg[CEC_MAX_MSG_SIZE]; + __u8 reply; + __u8 tx_arb_lost_cnt; + __u8 tx_nack_cnt; + __u8 tx_low_drive_cnt; + __u8 tx_error_cnt; +}; + +/** + * cec_msg_initiator - return the initiator's logical address. + * @msg: the message structure + */ +static inline __u8 cec_msg_initiator(const struct cec_msg *msg) +{ + return msg->msg[0] >> 4; +} + +/** + * cec_msg_destination - return the destination's logical address. + * @msg: the message structure + */ +static inline __u8 cec_msg_destination(const struct cec_msg *msg) +{ + return msg->msg[0] & 0xf; +} + +/** + * cec_msg_opcode - return the opcode of the message, -1 for poll + * @msg: the message structure + */ +static inline int cec_msg_opcode(const struct cec_msg *msg) +{ + return msg->len > 1 ? msg->msg[1] : -1; +} + +/** + * cec_msg_is_broadcast - return true if this is a broadcast message. + * @msg: the message structure + */ +static inline bool cec_msg_is_broadcast(const struct cec_msg *msg) +{ + return (msg->msg[0] & 0xf) == 0xf; +} + +/** + * cec_msg_init - initialize the message structure. + * @msg: the message structure + * @initiator: the logical address of the initiator + * @destination:the logical address of the destination (0xf for broadcast) + * + * The whole structure is zeroed, the len field is set to 1 (i.e. a poll + * message) and the initiator and destination are filled in. + */ +static inline void cec_msg_init(struct cec_msg *msg, + __u8 initiator, __u8 destination) +{ + memset(msg, 0, sizeof(*msg)); + msg->msg[0] = (initiator << 4) | destination; + msg->len = 1; +} + +/** + * cec_msg_set_reply_to - fill in destination/initiator in a reply message. + * @msg: the message structure for the reply + * @orig: the original message structure + * + * Set the msg destination to the orig initiator and the msg initiator to the + * orig destination. Note that msg and orig may be the same pointer, in which + * case the change is done in place. + */ +static inline void cec_msg_set_reply_to(struct cec_msg *msg, + struct cec_msg *orig) +{ + /* The destination becomes the initiator and vice versa */ + msg->msg[0] = (cec_msg_destination(orig) << 4) | + cec_msg_initiator(orig); + msg->reply = msg->timeout = 0; +} + +/* cec status field */ +#define CEC_TX_STATUS_OK (1 << 0) +#define CEC_TX_STATUS_ARB_LOST (1 << 1) +#define CEC_TX_STATUS_NACK (1 << 2) +#define CEC_TX_STATUS_LOW_DRIVE (1 << 3) +#define CEC_TX_STATUS_ERROR (1 << 4) +#define CEC_TX_STATUS_MAX_RETRIES (1 << 5) + +#define CEC_RX_STATUS_OK (1 << 0) +#define CEC_RX_STATUS_TIMEOUT (1 << 1) +#define CEC_RX_STATUS_FEATURE_ABORT (1 << 2) + +static inline bool cec_msg_status_is_ok(const struct cec_msg *msg) +{ + if (msg->tx_status && !(msg->tx_status & CEC_TX_STATUS_OK)) + return false; + if (msg->rx_status && !(msg->rx_status & CEC_RX_STATUS_OK)) + return false; + if (!msg->tx_status && !msg->rx_status) + return false; + return !(msg->rx_status & CEC_RX_STATUS_FEATURE_ABORT); +} + +#define CEC_LOG_ADDR_INVALID 0xff +#define CEC_PHYS_ADDR_INVALID 0xffff + +/* + * The maximum number of logical addresses one device can be assigned to. + * The CEC 2.0 spec allows for only 2 logical addresses at the moment. The + * Analog Devices CEC hardware supports 3. So let's go wild and go for 4. + */ +#define CEC_MAX_LOG_ADDRS 4 + +/* The logical addresses defined by CEC 2.0 */ +#define CEC_LOG_ADDR_TV 0 +#define CEC_LOG_ADDR_RECORD_1 1 +#define CEC_LOG_ADDR_RECORD_2 2 +#define CEC_LOG_ADDR_TUNER_1 3 +#define CEC_LOG_ADDR_PLAYBACK_1 4 +#define CEC_LOG_ADDR_AUDIOSYSTEM 5 +#define CEC_LOG_ADDR_TUNER_2 6 +#define CEC_LOG_ADDR_TUNER_3 7 +#define CEC_LOG_ADDR_PLAYBACK_2 8 +#define CEC_LOG_ADDR_RECORD_3 9 +#define CEC_LOG_ADDR_TUNER_4 10 +#define CEC_LOG_ADDR_PLAYBACK_3 11 +#define CEC_LOG_ADDR_BACKUP_1 12 +#define CEC_LOG_ADDR_BACKUP_2 13 +#define CEC_LOG_ADDR_SPECIFIC 14 +#define CEC_LOG_ADDR_UNREGISTERED 15 /* as initiator address */ +#define CEC_LOG_ADDR_BROADCAST 15 /* ad destination address */ + +/* The logical address types that the CEC device wants to claim */ +#define CEC_LOG_ADDR_TYPE_TV 0 +#define CEC_LOG_ADDR_TYPE_RECORD 1 +#define CEC_LOG_ADDR_TYPE_TUNER 2 +#define CEC_LOG_ADDR_TYPE_PLAYBACK 3 +#define CEC_LOG_ADDR_TYPE_AUDIOSYSTEM 4 +#define CEC_LOG_ADDR_TYPE_SPECIFIC 5 +#define CEC_LOG_ADDR_TYPE_UNREGISTERED 6 +/* + * Switches should use UNREGISTERED. + * Processors should use SPECIFIC. + */ + +#define CEC_LOG_ADDR_MASK_TV (1 << CEC_LOG_ADDR_TV) +#define CEC_LOG_ADDR_MASK_RECORD ((1 << CEC_LOG_ADDR_RECORD_1) | \ + (1 << CEC_LOG_ADDR_RECORD_2) | \ + (1 << CEC_LOG_ADDR_RECORD_3)) +#define CEC_LOG_ADDR_MASK_TUNER ((1 << CEC_LOG_ADDR_TUNER_1) | \ + (1 << CEC_LOG_ADDR_TUNER_2) | \ + (1 << CEC_LOG_ADDR_TUNER_3) | \ + (1 << CEC_LOG_ADDR_TUNER_4)) +#define CEC_LOG_ADDR_MASK_PLAYBACK ((1 << CEC_LOG_ADDR_PLAYBACK_1) | \ + (1 << CEC_LOG_ADDR_PLAYBACK_2) | \ + (1 << CEC_LOG_ADDR_PLAYBACK_3)) +#define CEC_LOG_ADDR_MASK_AUDIOSYSTEM (1 << CEC_LOG_ADDR_AUDIOSYSTEM) +#define CEC_LOG_ADDR_MASK_BACKUP ((1 << CEC_LOG_ADDR_BACKUP_1) | \ + (1 << CEC_LOG_ADDR_BACKUP_2)) +#define CEC_LOG_ADDR_MASK_SPECIFIC (1 << CEC_LOG_ADDR_SPECIFIC) +#define CEC_LOG_ADDR_MASK_UNREGISTERED (1 << CEC_LOG_ADDR_UNREGISTERED) + +static inline bool cec_has_tv(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_TV; +} + +static inline bool cec_has_record(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_RECORD; +} + +static inline bool cec_has_tuner(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_TUNER; +} + +static inline bool cec_has_playback(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_PLAYBACK; +} + +static inline bool cec_has_audiosystem(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_AUDIOSYSTEM; +} + +static inline bool cec_has_backup(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_BACKUP; +} + +static inline bool cec_has_specific(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_SPECIFIC; +} + +static inline bool cec_is_unregistered(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_UNREGISTERED; +} + +static inline bool cec_is_unconfigured(__u16 log_addr_mask) +{ + return log_addr_mask == 0; +} + +/* + * Use this if there is no vendor ID (CEC_G_VENDOR_ID) or if the vendor ID + * should be disabled (CEC_S_VENDOR_ID) + */ +#define CEC_VENDOR_ID_NONE 0xffffffff + +/* The message handling modes */ +/* Modes for initiator */ +#define CEC_MODE_NO_INITIATOR (0x0 << 0) +#define CEC_MODE_INITIATOR (0x1 << 0) +#define CEC_MODE_EXCL_INITIATOR (0x2 << 0) +#define CEC_MODE_INITIATOR_MSK 0x0f + +/* Modes for follower */ +#define CEC_MODE_NO_FOLLOWER (0x0 << 4) +#define CEC_MODE_FOLLOWER (0x1 << 4) +#define CEC_MODE_EXCL_FOLLOWER (0x2 << 4) +#define CEC_MODE_EXCL_FOLLOWER_PASSTHRU (0x3 << 4) +#define CEC_MODE_MONITOR (0xe << 4) +#define CEC_MODE_MONITOR_ALL (0xf << 4) +#define CEC_MODE_FOLLOWER_MSK 0xf0 + +/* Userspace has to configure the physical address */ +#define CEC_CAP_PHYS_ADDR (1 << 0) +/* Userspace has to configure the logical addresses */ +#define CEC_CAP_LOG_ADDRS (1 << 1) +/* Userspace can transmit messages (and thus become follower as well) */ +#define CEC_CAP_TRANSMIT (1 << 2) +/* + * Passthrough all messages instead of processing them. + */ +#define CEC_CAP_PASSTHROUGH (1 << 3) +/* Supports remote control */ +#define CEC_CAP_RC (1 << 4) +/* Hardware can monitor all messages, not just directed and broadcast. */ +#define CEC_CAP_MONITOR_ALL (1 << 5) + +/** + * struct cec_caps - CEC capabilities structure. + * @driver: name of the CEC device driver. + * @name: name of the CEC device. @driver + @name must be unique. + * @available_log_addrs: number of available logical addresses. + * @capabilities: capabilities of the CEC adapter. + * @version: version of the CEC adapter framework. + */ +struct cec_caps { + char driver[32]; + char name[32]; + __u32 available_log_addrs; + __u32 capabilities; + __u32 version; +}; + +/** + * struct cec_log_addrs - CEC logical addresses structure. + * @log_addr: the claimed logical addresses. Set by the driver. + * @log_addr_mask: current logical address mask. Set by the driver. + * @cec_version: the CEC version that the adapter should implement. Set by the + * caller. + * @num_log_addrs: how many logical addresses should be claimed. Set by the + * caller. + * @vendor_id: the vendor ID of the device. Set by the caller. + * @flags: set to 0. + * @osd_name: the OSD name of the device. Set by the caller. + * @primary_device_type: the primary device type for each logical address. + * Set by the caller. + * @log_addr_type: the logical address types. Set by the caller. + * @all_device_types: CEC 2.0: all device types represented by the logical + * address. Set by the caller. + * @features: CEC 2.0: The logical address features. Set by the caller. + */ +struct cec_log_addrs { + __u8 log_addr[CEC_MAX_LOG_ADDRS]; + __u16 log_addr_mask; + __u8 cec_version; + __u8 num_log_addrs; + __u32 vendor_id; + __u32 flags; + char osd_name[15]; + __u8 primary_device_type[CEC_MAX_LOG_ADDRS]; + __u8 log_addr_type[CEC_MAX_LOG_ADDRS]; + + /* CEC 2.0 */ + __u8 all_device_types[CEC_MAX_LOG_ADDRS]; + __u8 features[CEC_MAX_LOG_ADDRS][12]; +}; + +/* Events */ + +/* Event that occurs when the adapter state changes */ +#define CEC_EVENT_STATE_CHANGE 1 +/* + * This event is sent when messages are lost because the application + * didn't empty the message queue in time + */ +#define CEC_EVENT_LOST_MSGS 2 + +#define CEC_EVENT_FL_INITIAL_STATE (1 << 0) + +/** + * struct cec_event_state_change - used when the CEC adapter changes state. + * @phys_addr: the current physical address + * @log_addr_mask: the current logical address mask + */ +struct cec_event_state_change { + __u16 phys_addr; + __u16 log_addr_mask; +}; + +/** + * struct cec_event_lost_msgs - tells you how many messages were lost due. + * @lost_msgs: how many messages were lost. + */ +struct cec_event_lost_msgs { + __u32 lost_msgs; +}; + +/** + * struct cec_event - CEC event structure + * @ts: the timestamp of when the event was sent. + * @event: the event. + * array. + * @state_change: the event payload for CEC_EVENT_STATE_CHANGE. + * @lost_msgs: the event payload for CEC_EVENT_LOST_MSGS. + * @raw: array to pad the union. + */ +struct cec_event { + __u64 ts; + __u32 event; + __u32 flags; + union { + struct cec_event_state_change state_change; + struct cec_event_lost_msgs lost_msgs; + __u32 raw[16]; + }; +}; + +/* ioctls */ + +/* Adapter capabilities */ +#define CEC_ADAP_G_CAPS _IOWR('a', 0, struct cec_caps) + +/* + * phys_addr is either 0 (if this is the CEC root device) + * or a valid physical address obtained from the sink's EDID + * as read by this CEC device (if this is a source device) + * or a physical address obtained and modified from a sink + * EDID and used for a sink CEC device. + * If nothing is connected, then phys_addr is 0xffff. + * See HDMI 1.4b, section 8.7 (Physical Address). + * + * The CEC_ADAP_S_PHYS_ADDR ioctl may not be available if that is handled + * internally. + */ +#define CEC_ADAP_G_PHYS_ADDR _IOR('a', 1, __u16) +#define CEC_ADAP_S_PHYS_ADDR _IOW('a', 2, __u16) + +/* + * Configure the CEC adapter. It sets the device type and which + * logical types it will try to claim. It will return which + * logical addresses it could actually claim. + * An error is returned if the adapter is disabled or if there + * is no physical address assigned. + */ + +#define CEC_ADAP_G_LOG_ADDRS _IOR('a', 3, struct cec_log_addrs) +#define CEC_ADAP_S_LOG_ADDRS _IOWR('a', 4, struct cec_log_addrs) + +/* Transmit/receive a CEC command */ +#define CEC_TRANSMIT _IOWR('a', 5, struct cec_msg) +#define CEC_RECEIVE _IOWR('a', 6, struct cec_msg) + +/* Dequeue CEC events */ +#define CEC_DQEVENT _IOWR('a', 7, struct cec_event) + +/* + * Get and set the message handling mode for this filehandle. + */ +#define CEC_G_MODE _IOR('a', 8, __u32) +#define CEC_S_MODE _IOW('a', 9, __u32) + +/* + * The remainder of this header defines all CEC messages and operands. + * The format matters since it the cec-ctl utility parses it to generate + * code for implementing all these messages. + * + * Comments ending with 'Feature' group messages for each feature. + * If messages are part of multiple features, then the "Has also" + * comment is used to list the previously defined messages that are + * supported by the feature. + * + * Before operands are defined a comment is added that gives the + * name of the operand and in brackets the variable name of the + * corresponding argument in the cec-funcs.h function. + */ + +/* Messages */ + +/* One Touch Play Feature */ +#define CEC_MSG_ACTIVE_SOURCE 0x82 +#define CEC_MSG_IMAGE_VIEW_ON 0x04 +#define CEC_MSG_TEXT_VIEW_ON 0x0d + + +/* Routing Control Feature */ + +/* + * Has also: + * CEC_MSG_ACTIVE_SOURCE + */ + +#define CEC_MSG_INACTIVE_SOURCE 0x9d +#define CEC_MSG_REQUEST_ACTIVE_SOURCE 0x85 +#define CEC_MSG_ROUTING_CHANGE 0x80 +#define CEC_MSG_ROUTING_INFORMATION 0x81 +#define CEC_MSG_SET_STREAM_PATH 0x86 + + +/* Standby Feature */ +#define CEC_MSG_STANDBY 0x36 + + +/* One Touch Record Feature */ +#define CEC_MSG_RECORD_OFF 0x0b +#define CEC_MSG_RECORD_ON 0x09 +/* Record Source Type Operand (rec_src_type) */ +#define CEC_OP_RECORD_SRC_OWN 1 +#define CEC_OP_RECORD_SRC_DIGITAL 2 +#define CEC_OP_RECORD_SRC_ANALOG 3 +#define CEC_OP_RECORD_SRC_EXT_PLUG 4 +#define CEC_OP_RECORD_SRC_EXT_PHYS_ADDR 5 +/* Service Identification Method Operand (service_id_method) */ +#define CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID 0 +#define CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL 1 +/* Digital Service Broadcast System Operand (dig_bcast_system) */ +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN 0x00 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN 0x01 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN 0x02 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS 0x08 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS 0x09 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T 0x0a +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE 0x10 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT 0x11 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T 0x12 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C 0x18 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S 0x19 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2 0x1a +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T 0x1b +/* Analogue Broadcast Type Operand (ana_bcast_type) */ +#define CEC_OP_ANA_BCAST_TYPE_CABLE 0 +#define CEC_OP_ANA_BCAST_TYPE_SATELLITE 1 +#define CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL 2 +/* Broadcast System Operand (bcast_system) */ +#define CEC_OP_BCAST_SYSTEM_PAL_BG 0x00 +#define CEC_OP_BCAST_SYSTEM_SECAM_LQ 0x01 /* SECAM L' */ +#define CEC_OP_BCAST_SYSTEM_PAL_M 0x02 +#define CEC_OP_BCAST_SYSTEM_NTSC_M 0x03 +#define CEC_OP_BCAST_SYSTEM_PAL_I 0x04 +#define CEC_OP_BCAST_SYSTEM_SECAM_DK 0x05 +#define CEC_OP_BCAST_SYSTEM_SECAM_BG 0x06 +#define CEC_OP_BCAST_SYSTEM_SECAM_L 0x07 +#define CEC_OP_BCAST_SYSTEM_PAL_DK 0x08 +#define CEC_OP_BCAST_SYSTEM_OTHER 0x1f +/* Channel Number Format Operand (channel_number_fmt) */ +#define CEC_OP_CHANNEL_NUMBER_FMT_1_PART 0x01 +#define CEC_OP_CHANNEL_NUMBER_FMT_2_PART 0x02 + +#define CEC_MSG_RECORD_STATUS 0x0a +/* Record Status Operand (rec_status) */ +#define CEC_OP_RECORD_STATUS_CUR_SRC 0x01 +#define CEC_OP_RECORD_STATUS_DIG_SERVICE 0x02 +#define CEC_OP_RECORD_STATUS_ANA_SERVICE 0x03 +#define CEC_OP_RECORD_STATUS_EXT_INPUT 0x04 +#define CEC_OP_RECORD_STATUS_NO_DIG_SERVICE 0x05 +#define CEC_OP_RECORD_STATUS_NO_ANA_SERVICE 0x06 +#define CEC_OP_RECORD_STATUS_NO_SERVICE 0x07 +#define CEC_OP_RECORD_STATUS_INVALID_EXT_PLUG 0x09 +#define CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR 0x0a +#define CEC_OP_RECORD_STATUS_UNSUP_CA 0x0b +#define CEC_OP_RECORD_STATUS_NO_CA_ENTITLEMENTS 0x0c +#define CEC_OP_RECORD_STATUS_CANT_COPY_SRC 0x0d +#define CEC_OP_RECORD_STATUS_NO_MORE_COPIES 0x0e +#define CEC_OP_RECORD_STATUS_NO_MEDIA 0x10 +#define CEC_OP_RECORD_STATUS_PLAYING 0x11 +#define CEC_OP_RECORD_STATUS_ALREADY_RECORDING 0x12 +#define CEC_OP_RECORD_STATUS_MEDIA_PROT 0x13 +#define CEC_OP_RECORD_STATUS_NO_SIGNAL 0x14 +#define CEC_OP_RECORD_STATUS_MEDIA_PROBLEM 0x15 +#define CEC_OP_RECORD_STATUS_NO_SPACE 0x16 +#define CEC_OP_RECORD_STATUS_PARENTAL_LOCK 0x17 +#define CEC_OP_RECORD_STATUS_TERMINATED_OK 0x1a +#define CEC_OP_RECORD_STATUS_ALREADY_TERM 0x1b +#define CEC_OP_RECORD_STATUS_OTHER 0x1f + +#define CEC_MSG_RECORD_TV_SCREEN 0x0f + + +/* Timer Programming Feature */ +#define CEC_MSG_CLEAR_ANALOGUE_TIMER 0x33 +/* Recording Sequence Operand (recording_seq) */ +#define CEC_OP_REC_SEQ_SUNDAY 0x01 +#define CEC_OP_REC_SEQ_MONDAY 0x02 +#define CEC_OP_REC_SEQ_TUESDAY 0x04 +#define CEC_OP_REC_SEQ_WEDNESDAY 0x08 +#define CEC_OP_REC_SEQ_THURSDAY 0x10 +#define CEC_OP_REC_SEQ_FRIDAY 0x20 +#define CEC_OP_REC_SEQ_SATERDAY 0x40 +#define CEC_OP_REC_SEQ_ONCE_ONLY 0x00 + +#define CEC_MSG_CLEAR_DIGITAL_TIMER 0x99 + +#define CEC_MSG_CLEAR_EXT_TIMER 0xa1 +/* External Source Specifier Operand (ext_src_spec) */ +#define CEC_OP_EXT_SRC_PLUG 0x04 +#define CEC_OP_EXT_SRC_PHYS_ADDR 0x05 + +#define CEC_MSG_SET_ANALOGUE_TIMER 0x34 +#define CEC_MSG_SET_DIGITAL_TIMER 0x97 +#define CEC_MSG_SET_EXT_TIMER 0xa2 + +#define CEC_MSG_SET_TIMER_PROGRAM_TITLE 0x67 +#define CEC_MSG_TIMER_CLEARED_STATUS 0x43 +/* Timer Cleared Status Data Operand (timer_cleared_status) */ +#define CEC_OP_TIMER_CLR_STAT_RECORDING 0x00 +#define CEC_OP_TIMER_CLR_STAT_NO_MATCHING 0x01 +#define CEC_OP_TIMER_CLR_STAT_NO_INFO 0x02 +#define CEC_OP_TIMER_CLR_STAT_CLEARED 0x80 + +#define CEC_MSG_TIMER_STATUS 0x35 +/* Timer Overlap Warning Operand (timer_overlap_warning) */ +#define CEC_OP_TIMER_OVERLAP_WARNING_NO_OVERLAP 0 +#define CEC_OP_TIMER_OVERLAP_WARNING_OVERLAP 1 +/* Media Info Operand (media_info) */ +#define CEC_OP_MEDIA_INFO_UNPROT_MEDIA 0 +#define CEC_OP_MEDIA_INFO_PROT_MEDIA 1 +#define CEC_OP_MEDIA_INFO_NO_MEDIA 2 +/* Programmed Indicator Operand (prog_indicator) */ +#define CEC_OP_PROG_IND_NOT_PROGRAMMED 0 +#define CEC_OP_PROG_IND_PROGRAMMED 1 +/* Programmed Info Operand (prog_info) */ +#define CEC_OP_PROG_INFO_ENOUGH_SPACE 0x08 +#define CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE 0x09 +#define CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE 0x0b +#define CEC_OP_PROG_INFO_NONE_AVAILABLE 0x0a +/* Not Programmed Error Info Operand (prog_error) */ +#define CEC_OP_PROG_ERROR_NO_FREE_TIMER 0x01 +#define CEC_OP_PROG_ERROR_DATE_OUT_OF_RANGE 0x02 +#define CEC_OP_PROG_ERROR_REC_SEQ_ERROR 0x03 +#define CEC_OP_PROG_ERROR_INV_EXT_PLUG 0x04 +#define CEC_OP_PROG_ERROR_INV_EXT_PHYS_ADDR 0x05 +#define CEC_OP_PROG_ERROR_CA_UNSUPP 0x06 +#define CEC_OP_PROG_ERROR_INSUF_CA_ENTITLEMENTS 0x07 +#define CEC_OP_PROG_ERROR_RESOLUTION_UNSUPP 0x08 +#define CEC_OP_PROG_ERROR_PARENTAL_LOCK 0x09 +#define CEC_OP_PROG_ERROR_CLOCK_FAILURE 0x0a +#define CEC_OP_PROG_ERROR_DUPLICATE 0x0e + + +/* System Information Feature */ +#define CEC_MSG_CEC_VERSION 0x9e +/* CEC Version Operand (cec_version) */ +#define CEC_OP_CEC_VERSION_1_3A 4 +#define CEC_OP_CEC_VERSION_1_4 5 +#define CEC_OP_CEC_VERSION_2_0 6 + +#define CEC_MSG_GET_CEC_VERSION 0x9f +#define CEC_MSG_GIVE_PHYSICAL_ADDR 0x83 +#define CEC_MSG_GET_MENU_LANGUAGE 0x91 +#define CEC_MSG_REPORT_PHYSICAL_ADDR 0x84 +/* Primary Device Type Operand (prim_devtype) */ +#define CEC_OP_PRIM_DEVTYPE_TV 0 +#define CEC_OP_PRIM_DEVTYPE_RECORD 1 +#define CEC_OP_PRIM_DEVTYPE_TUNER 3 +#define CEC_OP_PRIM_DEVTYPE_PLAYBACK 4 +#define CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM 5 +#define CEC_OP_PRIM_DEVTYPE_SWITCH 6 +#define CEC_OP_PRIM_DEVTYPE_PROCESSOR 7 + +#define CEC_MSG_SET_MENU_LANGUAGE 0x32 +#define CEC_MSG_REPORT_FEATURES 0xa6 /* HDMI 2.0 */ +/* All Device Types Operand (all_device_types) */ +#define CEC_OP_ALL_DEVTYPE_TV 0x80 +#define CEC_OP_ALL_DEVTYPE_RECORD 0x40 +#define CEC_OP_ALL_DEVTYPE_TUNER 0x20 +#define CEC_OP_ALL_DEVTYPE_PLAYBACK 0x10 +#define CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM 0x08 +#define CEC_OP_ALL_DEVTYPE_SWITCH 0x04 +/* + * And if you wondering what happened to PROCESSOR devices: those should + * be mapped to a SWITCH. + */ + +/* Valid for RC Profile and Device Feature operands */ +#define CEC_OP_FEAT_EXT 0x80 /* Extension bit */ +/* RC Profile Operand (rc_profile) */ +#define CEC_OP_FEAT_RC_TV_PROFILE_NONE 0x00 +#define CEC_OP_FEAT_RC_TV_PROFILE_1 0x02 +#define CEC_OP_FEAT_RC_TV_PROFILE_2 0x06 +#define CEC_OP_FEAT_RC_TV_PROFILE_3 0x0a +#define CEC_OP_FEAT_RC_TV_PROFILE_4 0x0e +#define CEC_OP_FEAT_RC_SRC_HAS_DEV_ROOT_MENU 0x50 +#define CEC_OP_FEAT_RC_SRC_HAS_DEV_SETUP_MENU 0x48 +#define CEC_OP_FEAT_RC_SRC_HAS_CONTENTS_MENU 0x44 +#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_TOP_MENU 0x42 +#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU 0x41 +/* Device Feature Operand (dev_features) */ +#define CEC_OP_FEAT_DEV_HAS_RECORD_TV_SCREEN 0x40 +#define CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING 0x20 +#define CEC_OP_FEAT_DEV_HAS_DECK_CONTROL 0x10 +#define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE 0x08 +#define CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX 0x04 +#define CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX 0x02 + +#define CEC_MSG_GIVE_FEATURES 0xa5 /* HDMI 2.0 */ + + +/* Deck Control Feature */ +#define CEC_MSG_DECK_CONTROL 0x42 +/* Deck Control Mode Operand (deck_control_mode) */ +#define CEC_OP_DECK_CTL_MODE_SKIP_FWD 1 +#define CEC_OP_DECK_CTL_MODE_SKIP_REV 2 +#define CEC_OP_DECK_CTL_MODE_STOP 3 +#define CEC_OP_DECK_CTL_MODE_EJECT 4 + +#define CEC_MSG_DECK_STATUS 0x1b +/* Deck Info Operand (deck_info) */ +#define CEC_OP_DECK_INFO_PLAY 0x11 +#define CEC_OP_DECK_INFO_RECORD 0x12 +#define CEC_OP_DECK_INFO_PLAY_REV 0x13 +#define CEC_OP_DECK_INFO_STILL 0x14 +#define CEC_OP_DECK_INFO_SLOW 0x15 +#define CEC_OP_DECK_INFO_SLOW_REV 0x16 +#define CEC_OP_DECK_INFO_FAST_FWD 0x17 +#define CEC_OP_DECK_INFO_FAST_REV 0x18 +#define CEC_OP_DECK_INFO_NO_MEDIA 0x19 +#define CEC_OP_DECK_INFO_STOP 0x1a +#define CEC_OP_DECK_INFO_SKIP_FWD 0x1b +#define CEC_OP_DECK_INFO_SKIP_REV 0x1c +#define CEC_OP_DECK_INFO_INDEX_SEARCH_FWD 0x1d +#define CEC_OP_DECK_INFO_INDEX_SEARCH_REV 0x1e +#define CEC_OP_DECK_INFO_OTHER 0x1f + +#define CEC_MSG_GIVE_DECK_STATUS 0x1a +/* Status Request Operand (status_req) */ +#define CEC_OP_STATUS_REQ_ON 1 +#define CEC_OP_STATUS_REQ_OFF 2 +#define CEC_OP_STATUS_REQ_ONCE 3 + +#define CEC_MSG_PLAY 0x41 +/* Play Mode Operand (play_mode) */ +#define CEC_OP_PLAY_MODE_PLAY_FWD 0x24 +#define CEC_OP_PLAY_MODE_PLAY_REV 0x20 +#define CEC_OP_PLAY_MODE_PLAY_STILL 0x25 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN 0x05 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED 0x06 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX 0x07 +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN 0x09 +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED 0x0a +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX 0x0b +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN 0x15 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED 0x16 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX 0x17 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN 0x19 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED 0x1a +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX 0x1b + + +/* Tuner Control Feature */ +#define CEC_MSG_GIVE_TUNER_DEVICE_STATUS 0x08 +#define CEC_MSG_SELECT_ANALOGUE_SERVICE 0x92 +#define CEC_MSG_SELECT_DIGITAL_SERVICE 0x93 +#define CEC_MSG_TUNER_DEVICE_STATUS 0x07 +/* Recording Flag Operand (rec_flag) */ +#define CEC_OP_REC_FLAG_USED 0 +#define CEC_OP_REC_FLAG_NOT_USED 1 +/* Tuner Display Info Operand (tuner_display_info) */ +#define CEC_OP_TUNER_DISPLAY_INFO_DIGITAL 0 +#define CEC_OP_TUNER_DISPLAY_INFO_NONE 1 +#define CEC_OP_TUNER_DISPLAY_INFO_ANALOGUE 2 + +#define CEC_MSG_TUNER_STEP_DECREMENT 0x06 +#define CEC_MSG_TUNER_STEP_INCREMENT 0x05 + + +/* Vendor Specific Commands Feature */ + +/* + * Has also: + * CEC_MSG_CEC_VERSION + * CEC_MSG_GET_CEC_VERSION + */ +#define CEC_MSG_DEVICE_VENDOR_ID 0x87 +#define CEC_MSG_GIVE_DEVICE_VENDOR_ID 0x8c +#define CEC_MSG_VENDOR_COMMAND 0x89 +#define CEC_MSG_VENDOR_COMMAND_WITH_ID 0xa0 +#define CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN 0x8a +#define CEC_MSG_VENDOR_REMOTE_BUTTON_UP 0x8b + + +/* OSD Display Feature */ +#define CEC_MSG_SET_OSD_STRING 0x64 +/* Display Control Operand (disp_ctl) */ +#define CEC_OP_DISP_CTL_DEFAULT 0x00 +#define CEC_OP_DISP_CTL_UNTIL_CLEARED 0x40 +#define CEC_OP_DISP_CTL_CLEAR 0x80 + + +/* Device OSD Transfer Feature */ +#define CEC_MSG_GIVE_OSD_NAME 0x46 +#define CEC_MSG_SET_OSD_NAME 0x47 + + +/* Device Menu Control Feature */ +#define CEC_MSG_MENU_REQUEST 0x8d +/* Menu Request Type Operand (menu_req) */ +#define CEC_OP_MENU_REQUEST_ACTIVATE 0x00 +#define CEC_OP_MENU_REQUEST_DEACTIVATE 0x01 +#define CEC_OP_MENU_REQUEST_QUERY 0x02 + +#define CEC_MSG_MENU_STATUS 0x8e +/* Menu State Operand (menu_state) */ +#define CEC_OP_MENU_STATE_ACTIVATED 0x00 +#define CEC_OP_MENU_STATE_DEACTIVATED 0x01 + +#define CEC_MSG_USER_CONTROL_PRESSED 0x44 +/* UI Broadcast Type Operand (ui_bcast_type) */ +#define CEC_OP_UI_BCAST_TYPE_TOGGLE_ALL 0x00 +#define CEC_OP_UI_BCAST_TYPE_TOGGLE_DIG_ANA 0x01 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE 0x10 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_T 0x20 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_CABLE 0x30 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_SAT 0x40 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL 0x50 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_T 0x60 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_CABLE 0x70 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_SAT 0x80 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT 0x90 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT2 0x91 +#define CEC_OP_UI_BCAST_TYPE_IP 0xa0 +/* UI Sound Presentation Control Operand (ui_snd_pres_ctl) */ +#define CEC_OP_UI_SND_PRES_CTL_DUAL_MONO 0x10 +#define CEC_OP_UI_SND_PRES_CTL_KARAOKE 0x20 +#define CEC_OP_UI_SND_PRES_CTL_DOWNMIX 0x80 +#define CEC_OP_UI_SND_PRES_CTL_REVERB 0x90 +#define CEC_OP_UI_SND_PRES_CTL_EQUALIZER 0xa0 +#define CEC_OP_UI_SND_PRES_CTL_BASS_UP 0xb1 +#define CEC_OP_UI_SND_PRES_CTL_BASS_NEUTRAL 0xb2 +#define CEC_OP_UI_SND_PRES_CTL_BASS_DOWN 0xb3 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_UP 0xc1 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_NEUTRAL 0xc2 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_DOWN 0xc3 + +#define CEC_MSG_USER_CONTROL_RELEASED 0x45 + + +/* Remote Control Passthrough Feature */ + +/* + * Has also: + * CEC_MSG_USER_CONTROL_PRESSED + * CEC_MSG_USER_CONTROL_RELEASED + */ + + +/* Power Status Feature */ +#define CEC_MSG_GIVE_DEVICE_POWER_STATUS 0x8f +#define CEC_MSG_REPORT_POWER_STATUS 0x90 +/* Power Status Operand (pwr_state) */ +#define CEC_OP_POWER_STATUS_ON 0 +#define CEC_OP_POWER_STATUS_STANDBY 1 +#define CEC_OP_POWER_STATUS_TO_ON 2 +#define CEC_OP_POWER_STATUS_TO_STANDBY 3 + + +/* General Protocol Messages */ +#define CEC_MSG_FEATURE_ABORT 0x00 +/* Abort Reason Operand (reason) */ +#define CEC_OP_ABORT_UNRECOGNIZED_OP 0 +#define CEC_OP_ABORT_INCORRECT_MODE 1 +#define CEC_OP_ABORT_NO_SOURCE 2 +#define CEC_OP_ABORT_INVALID_OP 3 +#define CEC_OP_ABORT_REFUSED 4 +#define CEC_OP_ABORT_UNDETERMINED 5 + +#define CEC_MSG_ABORT 0xff + + +/* System Audio Control Feature */ + +/* + * Has also: + * CEC_MSG_USER_CONTROL_PRESSED + * CEC_MSG_USER_CONTROL_RELEASED + */ +#define CEC_MSG_GIVE_AUDIO_STATUS 0x71 +#define CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS 0x7d +#define CEC_MSG_REPORT_AUDIO_STATUS 0x7a +/* Audio Mute Status Operand (aud_mute_status) */ +#define CEC_OP_AUD_MUTE_STATUS_OFF 0 +#define CEC_OP_AUD_MUTE_STATUS_ON 1 + +#define CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR 0xa3 +#define CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR 0xa4 +#define CEC_MSG_SET_SYSTEM_AUDIO_MODE 0x72 +/* System Audio Status Operand (sys_aud_status) */ +#define CEC_OP_SYS_AUD_STATUS_OFF 0 +#define CEC_OP_SYS_AUD_STATUS_ON 1 + +#define CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST 0x70 +#define CEC_MSG_SYSTEM_AUDIO_MODE_STATUS 0x7e +/* Audio Format ID Operand (audio_format_id) */ +#define CEC_OP_AUD_FMT_ID_CEA861 0 +#define CEC_OP_AUD_FMT_ID_CEA861_CXT 1 + + +/* Audio Rate Control Feature */ +#define CEC_MSG_SET_AUDIO_RATE 0x9a +/* Audio Rate Operand (audio_rate) */ +#define CEC_OP_AUD_RATE_OFF 0 +#define CEC_OP_AUD_RATE_WIDE_STD 1 +#define CEC_OP_AUD_RATE_WIDE_FAST 2 +#define CEC_OP_AUD_RATE_WIDE_SLOW 3 +#define CEC_OP_AUD_RATE_NARROW_STD 4 +#define CEC_OP_AUD_RATE_NARROW_FAST 5 +#define CEC_OP_AUD_RATE_NARROW_SLOW 6 + + +/* Audio Return Channel Control Feature */ +#define CEC_MSG_INITIATE_ARC 0xc0 +#define CEC_MSG_REPORT_ARC_INITIATED 0xc1 +#define CEC_MSG_REPORT_ARC_TERMINATED 0xc2 +#define CEC_MSG_REQUEST_ARC_INITIATION 0xc3 +#define CEC_MSG_REQUEST_ARC_TERMINATION 0xc4 +#define CEC_MSG_TERMINATE_ARC 0xc5 + + +/* Dynamic Audio Lipsync Feature */ +/* Only for CEC 2.0 and up */ +#define CEC_MSG_REQUEST_CURRENT_LATENCY 0xa7 +#define CEC_MSG_REPORT_CURRENT_LATENCY 0xa8 +/* Low Latency Mode Operand (low_latency_mode) */ +#define CEC_OP_LOW_LATENCY_MODE_OFF 0 +#define CEC_OP_LOW_LATENCY_MODE_ON 1 +/* Audio Output Compensated Operand (audio_out_compensated) */ +#define CEC_OP_AUD_OUT_COMPENSATED_NA 0 +#define CEC_OP_AUD_OUT_COMPENSATED_DELAY 1 +#define CEC_OP_AUD_OUT_COMPENSATED_NO_DELAY 2 +#define CEC_OP_AUD_OUT_COMPENSATED_PARTIAL_DELAY 3 + + +/* Capability Discovery and Control Feature */ +#define CEC_MSG_CDC_MESSAGE 0xf8 +/* Ethernet-over-HDMI: nobody ever does this... */ +#define CEC_MSG_CDC_HEC_INQUIRE_STATE 0x00 +#define CEC_MSG_CDC_HEC_REPORT_STATE 0x01 +/* HEC Functionality State Operand (hec_func_state) */ +#define CEC_OP_HEC_FUNC_STATE_NOT_SUPPORTED 0 +#define CEC_OP_HEC_FUNC_STATE_INACTIVE 1 +#define CEC_OP_HEC_FUNC_STATE_ACTIVE 2 +#define CEC_OP_HEC_FUNC_STATE_ACTIVATION_FIELD 3 +/* Host Functionality State Operand (host_func_state) */ +#define CEC_OP_HOST_FUNC_STATE_NOT_SUPPORTED 0 +#define CEC_OP_HOST_FUNC_STATE_INACTIVE 1 +#define CEC_OP_HOST_FUNC_STATE_ACTIVE 2 +/* ENC Functionality State Operand (enc_func_state) */ +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED 0 +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_INACTIVE 1 +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_ACTIVE 2 +/* CDC Error Code Operand (cdc_errcode) */ +#define CEC_OP_CDC_ERROR_CODE_NONE 0 +#define CEC_OP_CDC_ERROR_CODE_CAP_UNSUPPORTED 1 +#define CEC_OP_CDC_ERROR_CODE_WRONG_STATE 2 +#define CEC_OP_CDC_ERROR_CODE_OTHER 3 +/* HEC Support Operand (hec_support) */ +#define CEC_OP_HEC_SUPPORT_NO 0 +#define CEC_OP_HEC_SUPPORT_YES 1 +/* HEC Activation Operand (hec_activation) */ +#define CEC_OP_HEC_ACTIVATION_ON 0 +#define CEC_OP_HEC_ACTIVATION_OFF 1 + +#define CEC_MSG_CDC_HEC_SET_STATE_ADJACENT 0x02 +#define CEC_MSG_CDC_HEC_SET_STATE 0x03 +/* HEC Set State Operand (hec_set_state) */ +#define CEC_OP_HEC_SET_STATE_DEACTIVATE 0 +#define CEC_OP_HEC_SET_STATE_ACTIVATE 1 + +#define CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION 0x04 +#define CEC_MSG_CDC_HEC_NOTIFY_ALIVE 0x05 +#define CEC_MSG_CDC_HEC_DISCOVER 0x06 +/* Hotplug Detect messages */ +#define CEC_MSG_CDC_HPD_SET_STATE 0x10 +/* HPD State Operand (hpd_state) */ +#define CEC_OP_HPD_STATE_CP_EDID_DISABLE 0 +#define CEC_OP_HPD_STATE_CP_EDID_ENABLE 1 +#define CEC_OP_HPD_STATE_CP_EDID_DISABLE_ENABLE 2 +#define CEC_OP_HPD_STATE_EDID_DISABLE 3 +#define CEC_OP_HPD_STATE_EDID_ENABLE 4 +#define CEC_OP_HPD_STATE_EDID_DISABLE_ENABLE 5 +#define CEC_MSG_CDC_HPD_REPORT_STATE 0x11 +/* HPD Error Code Operand (hpd_error) */ +#define CEC_OP_HPD_ERROR_NONE 0 +#define CEC_OP_HPD_ERROR_INITIATOR_NOT_CAPABLE 1 +#define CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE 2 +#define CEC_OP_HPD_ERROR_OTHER 3 +#define CEC_OP_HPD_ERROR_NONE_NO_VIDEO 4 + +#endif -- cgit v1.2.3 From 50f7d5a65e5a31e92a9d46663770cd9509f939a2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jun 2016 09:20:52 -0300 Subject: [media] cec-funcs.h: static inlines to pack/unpack CEC messages This public header contains static inlines to pack and unpack CEC messages. It is for use in both the kernel and in userspace. Since the CEC framework will initially be in staging this header is not yet in include/uapi. Once the framework is moved out of staging this header should be moved to uapi at the same time. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 1881 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1881 insertions(+) create mode 100644 include/linux/cec-funcs.h (limited to 'include') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h new file mode 100644 index 000000000000..8ee1029b9b74 --- /dev/null +++ b/include/linux/cec-funcs.h @@ -0,0 +1,1881 @@ +/* + * cec - HDMI Consumer Electronics Control message functions + * + * Copyright 2016 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. + */ + +/* + * Note: this framework is still in staging and it is likely the API + * will change before it goes out of staging. + * + * Once it is moved out of staging this header will move to uapi. + */ +#ifndef _CEC_UAPI_FUNCS_H +#define _CEC_UAPI_FUNCS_H + +#include + +/* One Touch Play Feature */ +static inline void cec_msg_active_source(struct cec_msg *msg, __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ACTIVE_SOURCE; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_active_source(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_image_view_on(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_IMAGE_VIEW_ON; +} + +static inline void cec_msg_text_view_on(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TEXT_VIEW_ON; +} + + +/* Routing Control Feature */ +static inline void cec_msg_inactive_source(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_INACTIVE_SOURCE; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_inactive_source(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_request_active_source(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REQUEST_ACTIVE_SOURCE; + msg->reply = reply ? CEC_MSG_ACTIVE_SOURCE : 0; +} + +static inline void cec_msg_routing_information(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ROUTING_INFORMATION; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_routing_information(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_routing_change(struct cec_msg *msg, + bool reply, + __u16 orig_phys_addr, + __u16 new_phys_addr) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ROUTING_CHANGE; + msg->msg[2] = orig_phys_addr >> 8; + msg->msg[3] = orig_phys_addr & 0xff; + msg->msg[4] = new_phys_addr >> 8; + msg->msg[5] = new_phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_ROUTING_INFORMATION : 0; +} + +static inline void cec_ops_routing_change(const struct cec_msg *msg, + __u16 *orig_phys_addr, + __u16 *new_phys_addr) +{ + *orig_phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *new_phys_addr = (msg->msg[4] << 8) | msg->msg[5]; +} + +static inline void cec_msg_set_stream_path(struct cec_msg *msg, __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_SET_STREAM_PATH; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_set_stream_path(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + + +/* Standby Feature */ +static inline void cec_msg_standby(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_STANDBY; +} + + +/* One Touch Record Feature */ +static inline void cec_msg_record_off(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_RECORD_OFF; +} + +struct cec_op_arib_data { + __u16 transport_id; + __u16 service_id; + __u16 orig_network_id; +}; + +struct cec_op_atsc_data { + __u16 transport_id; + __u16 program_number; +}; + +struct cec_op_dvb_data { + __u16 transport_id; + __u16 service_id; + __u16 orig_network_id; +}; + +struct cec_op_channel_data { + __u8 channel_number_fmt; + __u16 major; + __u16 minor; +}; + +struct cec_op_digital_service_id { + __u8 service_id_method; + __u8 dig_bcast_system; + union { + struct cec_op_arib_data arib; + struct cec_op_atsc_data atsc; + struct cec_op_dvb_data dvb; + struct cec_op_channel_data channel; + }; +}; + +struct cec_op_record_src { + __u8 type; + union { + struct cec_op_digital_service_id digital; + struct { + __u8 ana_bcast_type; + __u16 ana_freq; + __u8 bcast_system; + } analog; + struct { + __u8 plug; + } ext_plug; + struct { + __u16 phys_addr; + } ext_phys_addr; + }; +}; + +static inline void cec_set_digital_service_id(__u8 *msg, + const struct cec_op_digital_service_id *digital) +{ + *msg++ = (digital->service_id_method << 7) | digital->dig_bcast_system; + if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) { + *msg++ = (digital->channel.channel_number_fmt << 2) | + (digital->channel.major >> 8); + *msg++ = digital->channel.major && 0xff; + *msg++ = digital->channel.minor >> 8; + *msg++ = digital->channel.minor & 0xff; + *msg++ = 0; + *msg++ = 0; + return; + } + switch (digital->dig_bcast_system) { + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T: + *msg++ = digital->atsc.transport_id >> 8; + *msg++ = digital->atsc.transport_id & 0xff; + *msg++ = digital->atsc.program_number >> 8; + *msg++ = digital->atsc.program_number & 0xff; + *msg++ = 0; + *msg++ = 0; + break; + default: + *msg++ = digital->dvb.transport_id >> 8; + *msg++ = digital->dvb.transport_id & 0xff; + *msg++ = digital->dvb.service_id >> 8; + *msg++ = digital->dvb.service_id & 0xff; + *msg++ = digital->dvb.orig_network_id >> 8; + *msg++ = digital->dvb.orig_network_id & 0xff; + break; + } +} + +static inline void cec_get_digital_service_id(const __u8 *msg, + struct cec_op_digital_service_id *digital) +{ + digital->service_id_method = msg[0] >> 7; + digital->dig_bcast_system = msg[0] & 0x7f; + if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) { + digital->channel.channel_number_fmt = msg[1] >> 2; + digital->channel.major = ((msg[1] & 3) << 6) | msg[2]; + digital->channel.minor = (msg[3] << 8) | msg[4]; + return; + } + digital->dvb.transport_id = (msg[1] << 8) | msg[2]; + digital->dvb.service_id = (msg[3] << 8) | msg[4]; + digital->dvb.orig_network_id = (msg[5] << 8) | msg[6]; +} + +static inline void cec_msg_record_on_own(struct cec_msg *msg) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_OWN; +} + +static inline void cec_msg_record_on_digital(struct cec_msg *msg, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 10; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_DIGITAL; + cec_set_digital_service_id(msg->msg + 3, digital); +} + +static inline void cec_msg_record_on_analog(struct cec_msg *msg, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 7; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_ANALOG; + msg->msg[3] = ana_bcast_type; + msg->msg[4] = ana_freq >> 8; + msg->msg[5] = ana_freq & 0xff; + msg->msg[6] = bcast_system; +} + +static inline void cec_msg_record_on_plug(struct cec_msg *msg, + __u8 plug) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PLUG; + msg->msg[3] = plug; +} + +static inline void cec_msg_record_on_phys_addr(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 5; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PHYS_ADDR; + msg->msg[3] = phys_addr >> 8; + msg->msg[4] = phys_addr & 0xff; +} + +static inline void cec_msg_record_on(struct cec_msg *msg, + const struct cec_op_record_src *rec_src) +{ + switch (rec_src->type) { + case CEC_OP_RECORD_SRC_OWN: + cec_msg_record_on_own(msg); + break; + case CEC_OP_RECORD_SRC_DIGITAL: + cec_msg_record_on_digital(msg, &rec_src->digital); + break; + case CEC_OP_RECORD_SRC_ANALOG: + cec_msg_record_on_analog(msg, + rec_src->analog.ana_bcast_type, + rec_src->analog.ana_freq, + rec_src->analog.bcast_system); + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + cec_msg_record_on_plug(msg, rec_src->ext_plug.plug); + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + cec_msg_record_on_phys_addr(msg, + rec_src->ext_phys_addr.phys_addr); + break; + } +} + +static inline void cec_ops_record_on(const struct cec_msg *msg, + struct cec_op_record_src *rec_src) +{ + rec_src->type = msg->msg[2]; + switch (rec_src->type) { + case CEC_OP_RECORD_SRC_OWN: + break; + case CEC_OP_RECORD_SRC_DIGITAL: + cec_get_digital_service_id(msg->msg + 3, &rec_src->digital); + break; + case CEC_OP_RECORD_SRC_ANALOG: + rec_src->analog.ana_bcast_type = msg->msg[3]; + rec_src->analog.ana_freq = + (msg->msg[4] << 8) | msg->msg[5]; + rec_src->analog.bcast_system = msg->msg[6]; + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + rec_src->ext_plug.plug = msg->msg[3]; + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + rec_src->ext_phys_addr.phys_addr = + (msg->msg[3] << 8) | msg->msg[4]; + break; + } +} + +static inline void cec_msg_record_status(struct cec_msg *msg, __u8 rec_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_RECORD_STATUS; + msg->msg[2] = rec_status; +} + +static inline void cec_ops_record_status(const struct cec_msg *msg, + __u8 *rec_status) +{ + *rec_status = msg->msg[2]; +} + +static inline void cec_msg_record_tv_screen(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_RECORD_TV_SCREEN; + msg->reply = reply ? CEC_MSG_RECORD_ON : 0; +} + + +/* Timer Programming Feature */ +static inline void cec_msg_timer_status(struct cec_msg *msg, + __u8 timer_overlap_warning, + __u8 media_info, + __u8 prog_info, + __u8 prog_error, + __u8 duration_hr, + __u8 duration_min) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_TIMER_STATUS; + msg->msg[2] = (timer_overlap_warning << 7) | + (media_info << 5) | + (prog_info ? 0x10 : 0) | + (prog_info ? prog_info : prog_error); + if (prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE || + prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE || + prog_error == CEC_OP_PROG_ERROR_DUPLICATE) { + msg->len += 2; + msg->msg[3] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[4] = ((duration_min / 10) << 4) | (duration_min % 10); + } +} + +static inline void cec_ops_timer_status(struct cec_msg *msg, + __u8 *timer_overlap_warning, + __u8 *media_info, + __u8 *prog_info, + __u8 *prog_error, + __u8 *duration_hr, + __u8 *duration_min) +{ + *timer_overlap_warning = msg->msg[2] >> 7; + *media_info = (msg->msg[2] >> 5) & 3; + if (msg->msg[2] & 0x10) { + *prog_info = msg->msg[2] & 0xf; + *prog_error = 0; + } else { + *prog_info = 0; + *prog_error = msg->msg[2] & 0xf; + } + if (*prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE || + *prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE || + *prog_error == CEC_OP_PROG_ERROR_DUPLICATE) { + *duration_hr = (msg->msg[3] >> 4) * 10 + (msg->msg[3] & 0xf); + *duration_min = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + } else { + *duration_hr = *duration_min = 0; + } +} + +static inline void cec_msg_timer_cleared_status(struct cec_msg *msg, + __u8 timer_cleared_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_TIMER_CLEARED_STATUS; + msg->msg[2] = timer_cleared_status; +} + +static inline void cec_ops_timer_cleared_status(struct cec_msg *msg, + __u8 *timer_cleared_status) +{ + *timer_cleared_status = msg->msg[2]; +} + +static inline void cec_msg_clear_analogue_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_CLEAR_ANALOGUE_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ana_bcast_type; + msg->msg[10] = ana_freq >> 8; + msg->msg[11] = ana_freq & 0xff; + msg->msg[12] = bcast_system; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; +} + +static inline void cec_ops_clear_analogue_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ana_bcast_type = msg->msg[9]; + *ana_freq = (msg->msg[10] << 8) | msg->msg[11]; + *bcast_system = msg->msg[12]; +} + +static inline void cec_msg_clear_digital_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 16; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; + msg->msg[1] = CEC_MSG_CLEAR_DIGITAL_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + cec_set_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_ops_clear_digital_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + struct cec_op_digital_service_id *digital) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + cec_get_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_msg_clear_ext_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ext_src_spec, + __u8 plug, + __u16 phys_addr) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_CLEAR_EXT_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ext_src_spec; + msg->msg[10] = plug; + msg->msg[11] = phys_addr >> 8; + msg->msg[12] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; +} + +static inline void cec_ops_clear_ext_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ext_src_spec, + __u8 *plug, + __u16 *phys_addr) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ext_src_spec = msg->msg[9]; + *plug = msg->msg[10]; + *phys_addr = (msg->msg[11] << 8) | msg->msg[12]; +} + +static inline void cec_msg_set_analogue_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_SET_ANALOGUE_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ana_bcast_type; + msg->msg[10] = ana_freq >> 8; + msg->msg[11] = ana_freq & 0xff; + msg->msg[12] = bcast_system; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; +} + +static inline void cec_ops_set_analogue_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ana_bcast_type = msg->msg[9]; + *ana_freq = (msg->msg[10] << 8) | msg->msg[11]; + *bcast_system = msg->msg[12]; +} + +static inline void cec_msg_set_digital_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 16; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; + msg->msg[1] = CEC_MSG_SET_DIGITAL_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + cec_set_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_ops_set_digital_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + struct cec_op_digital_service_id *digital) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + cec_get_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_msg_set_ext_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ext_src_spec, + __u8 plug, + __u16 phys_addr) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_SET_EXT_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ext_src_spec; + msg->msg[10] = plug; + msg->msg[11] = phys_addr >> 8; + msg->msg[12] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; +} + +static inline void cec_ops_set_ext_timer(struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ext_src_spec, + __u8 *plug, + __u16 *phys_addr) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ext_src_spec = msg->msg[9]; + *plug = msg->msg[10]; + *phys_addr = (msg->msg[11] << 8) | msg->msg[12]; +} + +static inline void cec_msg_set_timer_program_title(struct cec_msg *msg, + const char *prog_title) +{ + unsigned int len = strlen(prog_title); + + if (len > 14) + len = 14; + msg->len = 2 + len; + msg->msg[1] = CEC_MSG_SET_TIMER_PROGRAM_TITLE; + memcpy(msg->msg + 2, prog_title, len); +} + +static inline void cec_ops_set_timer_program_title(const struct cec_msg *msg, + char *prog_title) +{ + unsigned int len = msg->len - 2; + + if (len > 14) + len = 14; + memcpy(prog_title, msg->msg + 2, len); + prog_title[len] = '\0'; +} + +/* System Information Feature */ +static inline void cec_msg_cec_version(struct cec_msg *msg, __u8 cec_version) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_CEC_VERSION; + msg->msg[2] = cec_version; +} + +static inline void cec_ops_cec_version(const struct cec_msg *msg, + __u8 *cec_version) +{ + *cec_version = msg->msg[2]; +} + +static inline void cec_msg_get_cec_version(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GET_CEC_VERSION; + msg->reply = reply ? CEC_MSG_CEC_VERSION : 0; +} + +static inline void cec_msg_report_physical_addr(struct cec_msg *msg, + __u16 phys_addr, __u8 prim_devtype) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_PHYSICAL_ADDR; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->msg[4] = prim_devtype; +} + +static inline void cec_ops_report_physical_addr(const struct cec_msg *msg, + __u16 *phys_addr, __u8 *prim_devtype) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *prim_devtype = msg->msg[4]; +} + +static inline void cec_msg_give_physical_addr(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_PHYSICAL_ADDR; + msg->reply = reply ? CEC_MSG_REPORT_PHYSICAL_ADDR : 0; +} + +static inline void cec_msg_set_menu_language(struct cec_msg *msg, + const char *language) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_SET_MENU_LANGUAGE; + memcpy(msg->msg + 2, language, 3); +} + +static inline void cec_ops_set_menu_language(struct cec_msg *msg, + char *language) +{ + memcpy(language, msg->msg + 2, 3); + language[3] = '\0'; +} + +static inline void cec_msg_get_menu_language(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GET_MENU_LANGUAGE; + msg->reply = reply ? CEC_MSG_SET_MENU_LANGUAGE : 0; +} + +/* + * Assumes a single RC Profile byte and a single Device Features byte, + * i.e. no extended features are supported by this helper function. + * + * As of CEC 2.0 no extended features are defined, should those be added + * in the future, then this function needs to be adapted or a new function + * should be added. + */ +static inline void cec_msg_report_features(struct cec_msg *msg, + __u8 cec_version, __u8 all_device_types, + __u8 rc_profile, __u8 dev_features) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_FEATURES; + msg->msg[2] = cec_version; + msg->msg[3] = all_device_types; + msg->msg[4] = rc_profile; + msg->msg[5] = dev_features; +} + +static inline void cec_ops_report_features(const struct cec_msg *msg, + __u8 *cec_version, __u8 *all_device_types, + const __u8 **rc_profile, const __u8 **dev_features) +{ + const __u8 *p = &msg->msg[4]; + + *cec_version = msg->msg[2]; + *all_device_types = msg->msg[3]; + *rc_profile = p; + while (p < &msg->msg[14] && (*p & CEC_OP_FEAT_EXT)) + p++; + if (!(*p & CEC_OP_FEAT_EXT)) { + *dev_features = p + 1; + while (p < &msg->msg[15] && (*p & CEC_OP_FEAT_EXT)) + p++; + } + if (*p & CEC_OP_FEAT_EXT) + *rc_profile = *dev_features = NULL; +} + +static inline void cec_msg_give_features(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_FEATURES; + msg->reply = reply ? CEC_MSG_REPORT_FEATURES : 0; +} + +/* Deck Control Feature */ +static inline void cec_msg_deck_control(struct cec_msg *msg, + __u8 deck_control_mode) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_DECK_CONTROL; + msg->msg[2] = deck_control_mode; +} + +static inline void cec_ops_deck_control(struct cec_msg *msg, + __u8 *deck_control_mode) +{ + *deck_control_mode = msg->msg[2]; +} + +static inline void cec_msg_deck_status(struct cec_msg *msg, + __u8 deck_info) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_DECK_STATUS; + msg->msg[2] = deck_info; +} + +static inline void cec_ops_deck_status(struct cec_msg *msg, + __u8 *deck_info) +{ + *deck_info = msg->msg[2]; +} + +static inline void cec_msg_give_deck_status(struct cec_msg *msg, + bool reply, + __u8 status_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_GIVE_DECK_STATUS; + msg->msg[2] = status_req; + msg->reply = reply ? CEC_MSG_DECK_STATUS : 0; +} + +static inline void cec_ops_give_deck_status(struct cec_msg *msg, + __u8 *status_req) +{ + *status_req = msg->msg[2]; +} + +static inline void cec_msg_play(struct cec_msg *msg, + __u8 play_mode) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_PLAY; + msg->msg[2] = play_mode; +} + +static inline void cec_ops_play(struct cec_msg *msg, + __u8 *play_mode) +{ + *play_mode = msg->msg[2]; +} + + +/* Tuner Control Feature */ +struct cec_op_tuner_device_info { + __u8 rec_flag; + __u8 tuner_display_info; + bool is_analog; + union { + struct cec_op_digital_service_id digital; + struct { + __u8 ana_bcast_type; + __u16 ana_freq; + __u8 bcast_system; + } analog; + }; +}; + +static inline void cec_msg_tuner_device_status_analog(struct cec_msg *msg, + __u8 rec_flag, + __u8 tuner_display_info, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 7; + msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS; + msg->msg[2] = (rec_flag << 7) | tuner_display_info; + msg->msg[3] = ana_bcast_type; + msg->msg[4] = ana_freq >> 8; + msg->msg[5] = ana_freq & 0xff; + msg->msg[6] = bcast_system; +} + +static inline void cec_msg_tuner_device_status_digital(struct cec_msg *msg, + __u8 rec_flag, __u8 tuner_display_info, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 10; + msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS; + msg->msg[2] = (rec_flag << 7) | tuner_display_info; + cec_set_digital_service_id(msg->msg + 3, digital); +} + +static inline void cec_msg_tuner_device_status(struct cec_msg *msg, + const struct cec_op_tuner_device_info *tuner_dev_info) +{ + if (tuner_dev_info->is_analog) + cec_msg_tuner_device_status_analog(msg, + tuner_dev_info->rec_flag, + tuner_dev_info->tuner_display_info, + tuner_dev_info->analog.ana_bcast_type, + tuner_dev_info->analog.ana_freq, + tuner_dev_info->analog.bcast_system); + else + cec_msg_tuner_device_status_digital(msg, + tuner_dev_info->rec_flag, + tuner_dev_info->tuner_display_info, + &tuner_dev_info->digital); +} + +static inline void cec_ops_tuner_device_status(struct cec_msg *msg, + struct cec_op_tuner_device_info *tuner_dev_info) +{ + tuner_dev_info->is_analog = msg->len < 10; + tuner_dev_info->rec_flag = msg->msg[2] >> 7; + tuner_dev_info->tuner_display_info = msg->msg[2] & 0x7f; + if (tuner_dev_info->is_analog) { + tuner_dev_info->analog.ana_bcast_type = msg->msg[3]; + tuner_dev_info->analog.ana_freq = (msg->msg[4] << 8) | msg->msg[5]; + tuner_dev_info->analog.bcast_system = msg->msg[6]; + return; + } + cec_get_digital_service_id(msg->msg + 3, &tuner_dev_info->digital); +} + +static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg, + bool reply, + __u8 status_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS; + msg->msg[2] = status_req; + msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0; +} + +static inline void cec_ops_give_tuner_device_status(struct cec_msg *msg, + __u8 *status_req) +{ + *status_req = msg->msg[2]; +} + +static inline void cec_msg_select_analogue_service(struct cec_msg *msg, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 6; + msg->msg[1] = CEC_MSG_SELECT_ANALOGUE_SERVICE; + msg->msg[2] = ana_bcast_type; + msg->msg[3] = ana_freq >> 8; + msg->msg[4] = ana_freq & 0xff; + msg->msg[5] = bcast_system; +} + +static inline void cec_ops_select_analogue_service(struct cec_msg *msg, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *ana_bcast_type = msg->msg[2]; + *ana_freq = (msg->msg[3] << 8) | msg->msg[4]; + *bcast_system = msg->msg[5]; +} + +static inline void cec_msg_select_digital_service(struct cec_msg *msg, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 9; + msg->msg[1] = CEC_MSG_SELECT_DIGITAL_SERVICE; + cec_set_digital_service_id(msg->msg + 2, digital); +} + +static inline void cec_ops_select_digital_service(struct cec_msg *msg, + struct cec_op_digital_service_id *digital) +{ + cec_get_digital_service_id(msg->msg + 2, digital); +} + +static inline void cec_msg_tuner_step_decrement(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TUNER_STEP_DECREMENT; +} + +static inline void cec_msg_tuner_step_increment(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TUNER_STEP_INCREMENT; +} + + +/* Vendor Specific Commands Feature */ +static inline void cec_msg_device_vendor_id(struct cec_msg *msg, __u32 vendor_id) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_DEVICE_VENDOR_ID; + msg->msg[2] = vendor_id >> 16; + msg->msg[3] = (vendor_id >> 8) & 0xff; + msg->msg[4] = vendor_id & 0xff; +} + +static inline void cec_ops_device_vendor_id(const struct cec_msg *msg, + __u32 *vendor_id) +{ + *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4]; +} + +static inline void cec_msg_give_device_vendor_id(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_DEVICE_VENDOR_ID; + msg->reply = reply ? CEC_MSG_DEVICE_VENDOR_ID : 0; +} + +static inline void cec_msg_vendor_remote_button_up(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_UP; +} + + +/* OSD Display Feature */ +static inline void cec_msg_set_osd_string(struct cec_msg *msg, + __u8 disp_ctl, + const char *osd) +{ + unsigned int len = strlen(osd); + + if (len > 13) + len = 13; + msg->len = 3 + len; + msg->msg[1] = CEC_MSG_SET_OSD_STRING; + msg->msg[2] = disp_ctl; + memcpy(msg->msg + 3, osd, len); +} + +static inline void cec_ops_set_osd_string(const struct cec_msg *msg, + __u8 *disp_ctl, + char *osd) +{ + unsigned int len = msg->len - 3; + + *disp_ctl = msg->msg[2]; + if (len > 13) + len = 13; + memcpy(osd, msg->msg + 3, len); + osd[len] = '\0'; +} + + +/* Device OSD Transfer Feature */ +static inline void cec_msg_set_osd_name(struct cec_msg *msg, const char *name) +{ + unsigned int len = strlen(name); + + if (len > 14) + len = 14; + msg->len = 2 + len; + msg->msg[1] = CEC_MSG_SET_OSD_NAME; + memcpy(msg->msg + 2, name, len); +} + +static inline void cec_ops_set_osd_name(const struct cec_msg *msg, + char *name) +{ + unsigned int len = msg->len - 2; + + if (len > 14) + len = 14; + memcpy(name, msg->msg + 2, len); + name[len] = '\0'; +} + +static inline void cec_msg_give_osd_name(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_OSD_NAME; + msg->reply = reply ? CEC_MSG_SET_OSD_NAME : 0; +} + + +/* Device Menu Control Feature */ +static inline void cec_msg_menu_status(struct cec_msg *msg, + __u8 menu_state) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_MENU_STATUS; + msg->msg[2] = menu_state; +} + +static inline void cec_ops_menu_status(struct cec_msg *msg, + __u8 *menu_state) +{ + *menu_state = msg->msg[2]; +} + +static inline void cec_msg_menu_request(struct cec_msg *msg, + bool reply, + __u8 menu_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_MENU_REQUEST; + msg->msg[2] = menu_req; + msg->reply = reply ? CEC_MSG_MENU_STATUS : 0; +} + +static inline void cec_ops_menu_request(struct cec_msg *msg, + __u8 *menu_req) +{ + *menu_req = msg->msg[2]; +} + +struct cec_op_ui_command { + __u8 ui_cmd; + bool has_opt_arg; + union { + struct cec_op_channel_data channel_identifier; + __u8 ui_broadcast_type; + __u8 ui_sound_presentation_control; + __u8 play_mode; + __u8 ui_function_media; + __u8 ui_function_select_av_input; + __u8 ui_function_select_audio_input; + }; +}; + +static inline void cec_msg_user_control_pressed(struct cec_msg *msg, + const struct cec_op_ui_command *ui_cmd) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_USER_CONTROL_PRESSED; + msg->msg[2] = ui_cmd->ui_cmd; + if (!ui_cmd->has_opt_arg) + return; + switch (ui_cmd->ui_cmd) { + case 0x56: + case 0x57: + case 0x60: + case 0x68: + case 0x69: + case 0x6a: + /* The optional operand is one byte for all these ui commands */ + msg->len++; + msg->msg[3] = ui_cmd->play_mode; + break; + case 0x67: + msg->len += 4; + msg->msg[3] = (ui_cmd->channel_identifier.channel_number_fmt << 2) | + (ui_cmd->channel_identifier.major >> 8); + msg->msg[4] = ui_cmd->channel_identifier.major && 0xff; + msg->msg[5] = ui_cmd->channel_identifier.minor >> 8; + msg->msg[6] = ui_cmd->channel_identifier.minor & 0xff; + break; + } +} + +static inline void cec_ops_user_control_pressed(struct cec_msg *msg, + struct cec_op_ui_command *ui_cmd) +{ + ui_cmd->ui_cmd = msg->msg[2]; + ui_cmd->has_opt_arg = false; + if (msg->len == 3) + return; + switch (ui_cmd->ui_cmd) { + case 0x56: + case 0x57: + case 0x60: + case 0x68: + case 0x69: + case 0x6a: + /* The optional operand is one byte for all these ui commands */ + ui_cmd->play_mode = msg->msg[3]; + ui_cmd->has_opt_arg = true; + break; + case 0x67: + if (msg->len < 7) + break; + ui_cmd->has_opt_arg = true; + ui_cmd->channel_identifier.channel_number_fmt = msg->msg[3] >> 2; + ui_cmd->channel_identifier.major = ((msg->msg[3] & 3) << 6) | msg->msg[4]; + ui_cmd->channel_identifier.minor = (msg->msg[5] << 8) | msg->msg[6]; + break; + } +} + +static inline void cec_msg_user_control_released(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_USER_CONTROL_RELEASED; +} + +/* Remote Control Passthrough Feature */ + +/* Power Status Feature */ +static inline void cec_msg_report_power_status(struct cec_msg *msg, + __u8 pwr_state) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_REPORT_POWER_STATUS; + msg->msg[2] = pwr_state; +} + +static inline void cec_ops_report_power_status(const struct cec_msg *msg, + __u8 *pwr_state) +{ + *pwr_state = msg->msg[2]; +} + +static inline void cec_msg_give_device_power_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_DEVICE_POWER_STATUS; + msg->reply = reply ? CEC_MSG_REPORT_POWER_STATUS : 0; +} + +/* General Protocol Messages */ +static inline void cec_msg_feature_abort(struct cec_msg *msg, + __u8 abort_msg, __u8 reason) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_FEATURE_ABORT; + msg->msg[2] = abort_msg; + msg->msg[3] = reason; +} + +static inline void cec_ops_feature_abort(const struct cec_msg *msg, + __u8 *abort_msg, __u8 *reason) +{ + *abort_msg = msg->msg[2]; + *reason = msg->msg[3]; +} + +/* This changes the current message into a feature abort message */ +static inline void cec_msg_reply_feature_abort(struct cec_msg *msg, __u8 reason) +{ + cec_msg_set_reply_to(msg, msg); + msg->len = 4; + msg->msg[2] = msg->msg[1]; + msg->msg[3] = reason; + msg->msg[1] = CEC_MSG_FEATURE_ABORT; +} + +static inline void cec_msg_abort(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_ABORT; +} + + +/* System Audio Control Feature */ +static inline void cec_msg_report_audio_status(struct cec_msg *msg, + __u8 aud_mute_status, + __u8 aud_vol_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_REPORT_AUDIO_STATUS; + msg->msg[2] = (aud_mute_status << 7) | (aud_vol_status & 0x7f); +} + +static inline void cec_ops_report_audio_status(const struct cec_msg *msg, + __u8 *aud_mute_status, + __u8 *aud_vol_status) +{ + *aud_mute_status = msg->msg[2] >> 7; + *aud_vol_status = msg->msg[2] & 0x7f; +} + +static inline void cec_msg_give_audio_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_AUDIO_STATUS; + msg->reply = reply ? CEC_MSG_REPORT_AUDIO_STATUS : 0; +} + +static inline void cec_msg_set_system_audio_mode(struct cec_msg *msg, + __u8 sys_aud_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SET_SYSTEM_AUDIO_MODE; + msg->msg[2] = sys_aud_status; +} + +static inline void cec_ops_set_system_audio_mode(const struct cec_msg *msg, + __u8 *sys_aud_status) +{ + *sys_aud_status = msg->msg[2]; +} + +static inline void cec_msg_system_audio_mode_request(struct cec_msg *msg, + bool reply, + __u16 phys_addr) +{ + msg->len = phys_addr == 0xffff ? 2 : 4; + msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_SET_SYSTEM_AUDIO_MODE : 0; + +} + +static inline void cec_ops_system_audio_mode_request(const struct cec_msg *msg, + __u16 *phys_addr) +{ + if (msg->len < 4) + *phys_addr = 0xffff; + else + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_system_audio_mode_status(struct cec_msg *msg, + __u8 sys_aud_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_STATUS; + msg->msg[2] = sys_aud_status; +} + +static inline void cec_ops_system_audio_mode_status(const struct cec_msg *msg, + __u8 *sys_aud_status) +{ + *sys_aud_status = msg->msg[2]; +} + +static inline void cec_msg_give_system_audio_mode_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS; + msg->reply = reply ? CEC_MSG_SYSTEM_AUDIO_MODE_STATUS : 0; +} + +static inline void cec_msg_report_short_audio_descriptor(struct cec_msg *msg, + __u8 num_descriptors, + const __u32 *descriptors) +{ + unsigned int i; + + if (num_descriptors > 4) + num_descriptors = 4; + msg->len = 2 + num_descriptors * 3; + msg->msg[1] = CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR; + for (i = 0; i < num_descriptors; i++) { + msg->msg[2 + i * 3] = (descriptors[i] >> 16) & 0xff; + msg->msg[3 + i * 3] = (descriptors[i] >> 8) & 0xff; + msg->msg[4 + i * 3] = descriptors[i] & 0xff; + } +} + +static inline void cec_ops_report_short_audio_descriptor(const struct cec_msg *msg, + __u8 *num_descriptors, + __u32 *descriptors) +{ + unsigned int i; + + *num_descriptors = (msg->len - 2) / 3; + if (*num_descriptors > 4) + *num_descriptors = 4; + for (i = 0; i < *num_descriptors; i++) + descriptors[i] = (msg->msg[2 + i * 3] << 16) | + (msg->msg[3 + i * 3] << 8) | + msg->msg[4 + i * 3]; +} + +static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg, + __u8 num_descriptors, + const __u8 *audio_format_id, + const __u8 *audio_format_code) +{ + unsigned int i; + + if (num_descriptors > 4) + num_descriptors = 4; + msg->len = 2 + num_descriptors; + msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR; + for (i = 0; i < num_descriptors; i++) + msg->msg[2 + i] = (audio_format_id[i] << 6) | + (audio_format_code[i] & 0x3f); +} + +static inline void cec_ops_request_short_audio_descriptor(const struct cec_msg *msg, + __u8 *num_descriptors, + __u8 *audio_format_id, + __u8 *audio_format_code) +{ + unsigned int i; + + *num_descriptors = msg->len - 2; + if (*num_descriptors > 4) + *num_descriptors = 4; + for (i = 0; i < *num_descriptors; i++) { + audio_format_id[i] = msg->msg[2 + i] >> 6; + audio_format_code[i] = msg->msg[2 + i] & 0x3f; + } +} + + +/* Audio Rate Control Feature */ +static inline void cec_msg_set_audio_rate(struct cec_msg *msg, + __u8 audio_rate) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SET_AUDIO_RATE; + msg->msg[2] = audio_rate; +} + +static inline void cec_ops_set_audio_rate(const struct cec_msg *msg, + __u8 *audio_rate) +{ + *audio_rate = msg->msg[2]; +} + + +/* Audio Return Channel Control Feature */ +static inline void cec_msg_report_arc_initiated(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REPORT_ARC_INITIATED; +} + +static inline void cec_msg_initiate_arc(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_INITIATE_ARC; + msg->reply = reply ? CEC_MSG_REPORT_ARC_INITIATED : 0; +} + +static inline void cec_msg_request_arc_initiation(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REQUEST_ARC_INITIATION; + msg->reply = reply ? CEC_MSG_INITIATE_ARC : 0; +} + +static inline void cec_msg_report_arc_terminated(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REPORT_ARC_TERMINATED; +} + +static inline void cec_msg_terminate_arc(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TERMINATE_ARC; + msg->reply = reply ? CEC_MSG_REPORT_ARC_TERMINATED : 0; +} + +static inline void cec_msg_request_arc_termination(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REQUEST_ARC_TERMINATION; + msg->reply = reply ? CEC_MSG_TERMINATE_ARC : 0; +} + + +/* Dynamic Audio Lipsync Feature */ +/* Only for CEC 2.0 and up */ +static inline void cec_msg_report_current_latency(struct cec_msg *msg, + __u16 phys_addr, + __u8 video_latency, + __u8 low_latency_mode, + __u8 audio_out_compensated, + __u8 audio_out_delay) +{ + msg->len = 7; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_CURRENT_LATENCY; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->msg[4] = video_latency; + msg->msg[5] = (low_latency_mode << 2) | audio_out_compensated; + msg->msg[6] = audio_out_delay; +} + +static inline void cec_ops_report_current_latency(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *video_latency, + __u8 *low_latency_mode, + __u8 *audio_out_compensated, + __u8 *audio_out_delay) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *video_latency = msg->msg[4]; + *low_latency_mode = (msg->msg[5] >> 2) & 1; + *audio_out_compensated = msg->msg[5] & 3; + *audio_out_delay = msg->msg[6]; +} + +static inline void cec_msg_request_current_latency(struct cec_msg *msg, + bool reply, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REQUEST_CURRENT_LATENCY; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_REPORT_CURRENT_LATENCY : 0; +} + +static inline void cec_ops_request_current_latency(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + + +/* Capability Discovery and Control Feature */ +static inline void cec_msg_cdc_hec_inquire_state(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2) +{ + msg->len = 9; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; +} + +static inline void cec_ops_cdc_hec_inquire_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; +} + +static inline void cec_msg_cdc_hec_report_state(struct cec_msg *msg, + __u16 target_phys_addr, + __u8 hec_func_state, + __u8 host_func_state, + __u8 enc_func_state, + __u8 cdc_errcode, + __u8 has_field, + __u16 hec_field) +{ + msg->len = has_field ? 10 : 8; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_REPORT_STATE; + msg->msg[5] = target_phys_addr >> 8; + msg->msg[6] = target_phys_addr & 0xff; + msg->msg[7] = (hec_func_state << 6) | + (host_func_state << 4) | + (enc_func_state << 2) | + cdc_errcode; + if (has_field) { + msg->msg[8] = hec_field >> 8; + msg->msg[9] = hec_field & 0xff; + } +} + +static inline void cec_ops_cdc_hec_report_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *target_phys_addr, + __u8 *hec_func_state, + __u8 *host_func_state, + __u8 *enc_func_state, + __u8 *cdc_errcode, + __u8 *has_field, + __u16 *hec_field) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *target_phys_addr = (msg->msg[5] << 8) | msg->msg[6]; + *hec_func_state = msg->msg[7] >> 6; + *host_func_state = (msg->msg[7] >> 4) & 3; + *enc_func_state = (msg->msg[7] >> 4) & 3; + *cdc_errcode = msg->msg[7] & 3; + *has_field = msg->len >= 10; + *hec_field = *has_field ? ((msg->msg[8] << 8) | msg->msg[9]) : 0; +} + +static inline void cec_msg_cdc_hec_set_state(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2, + __u8 hec_set_state, + __u16 phys_addr3, + __u16 phys_addr4, + __u16 phys_addr5) +{ + msg->len = 10; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; + msg->msg[9] = hec_set_state; + if (phys_addr3 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr3 >> 8; + msg->msg[msg->len++] = phys_addr3 & 0xff; + if (phys_addr4 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr4 >> 8; + msg->msg[msg->len++] = phys_addr4 & 0xff; + if (phys_addr5 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr5 >> 8; + msg->msg[msg->len++] = phys_addr5 & 0xff; + } + } + } +} + +static inline void cec_ops_cdc_hec_set_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2, + __u8 *hec_set_state, + __u16 *phys_addr3, + __u16 *phys_addr4, + __u16 *phys_addr5) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; + *hec_set_state = msg->msg[9]; + *phys_addr3 = *phys_addr4 = *phys_addr5 = CEC_PHYS_ADDR_INVALID; + if (msg->len >= 12) + *phys_addr3 = (msg->msg[10] << 8) | msg->msg[11]; + if (msg->len >= 14) + *phys_addr4 = (msg->msg[12] << 8) | msg->msg[13]; + if (msg->len >= 16) + *phys_addr5 = (msg->msg[14] << 8) | msg->msg[15]; +} + +static inline void cec_msg_cdc_hec_set_state_adjacent(struct cec_msg *msg, + __u16 phys_addr1, + __u8 hec_set_state) +{ + msg->len = 8; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_SET_STATE_ADJACENT; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = hec_set_state; +} + +static inline void cec_ops_cdc_hec_set_state_adjacent(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u8 *hec_set_state) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *hec_set_state = msg->msg[7]; +} + +static inline void cec_msg_cdc_hec_request_deactivation(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2, + __u16 phys_addr3) +{ + msg->len = 11; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; + msg->msg[9] = phys_addr3 >> 8; + msg->msg[10] = phys_addr3 & 0xff; +} + +static inline void cec_ops_cdc_hec_request_deactivation(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2, + __u16 *phys_addr3) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; + *phys_addr3 = (msg->msg[9] << 8) | msg->msg[10]; +} + +static inline void cec_msg_cdc_hec_notify_alive(struct cec_msg *msg) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_NOTIFY_ALIVE; +} + +static inline void cec_ops_cdc_hec_notify_alive(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_cdc_hec_discover(struct cec_msg *msg) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_DISCOVER; +} + +static inline void cec_ops_cdc_hec_discover(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_cdc_hpd_set_state(struct cec_msg *msg, + __u8 input_port, + __u8 hpd_state) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HPD_SET_STATE; + msg->msg[5] = (input_port << 4) | hpd_state; +} + +static inline void cec_ops_cdc_hpd_set_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *input_port, + __u8 *hpd_state) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *input_port = msg->msg[5] >> 4; + *hpd_state = msg->msg[5] & 0xf; +} + +static inline void cec_msg_cdc_hpd_report_state(struct cec_msg *msg, + __u8 hpd_state, + __u8 hpd_error) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HPD_REPORT_STATE; + msg->msg[5] = (hpd_state << 4) | hpd_error; +} + +static inline void cec_ops_cdc_hpd_report_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *hpd_state, + __u8 *hpd_error) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *hpd_state = msg->msg[5] >> 4; + *hpd_error = msg->msg[5] & 0xf; +} + +#endif -- cgit v1.2.3 From a56960e8b406d36b612776c79134b954adc2ca18 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Jun 2016 09:43:58 -0300 Subject: [media] cec: add HDMI CEC framework (core) The added HDMI CEC framework provides a generic kernel interface for HDMI CEC devices. Note that the CEC framework is added to staging/media and that the cec.h and cec-funcs.h headers are not exported yet. While the kABI is mature, I would prefer to allow the uABI some more time before it is mainlined in case it needs more tweaks. This adds the cec-core.c, media/cec.h and cec-priv.h sources. Signed-off-by: Hans Verkuil [k.debski@samsung.com: Merged CEC Updates commit by Hans Verkuil] [k.debski@samsung.com: Merged Update author commit by Hans Verkuil] [k.debski@samsung.com: code cleanup and fixes] [k.debski@samsung.com: add missing CEC commands to match spec] [k.debski@samsung.com: add RC framework support] [k.debski@samsung.com: move and edit documentation] [k.debski@samsung.com: add vendor id reporting] [k.debski@samsung.com: reorder of API structs and add reserved fields] [k.debski@samsung.com: fix handling of events and fix 32/64bit timespec problem] [k.debski@samsung.com: add sequence number handling] [k.debski@samsung.com: add passthrough mode] [k.debski@samsung.com: fix CEC defines, add missing CEC 2.0 commands] Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/cec/cec-core.c | 409 +++++++++++++++++++++++++++++++++++ drivers/staging/media/cec/cec-priv.h | 56 +++++ include/media/cec.h | 232 ++++++++++++++++++++ 3 files changed, 697 insertions(+) create mode 100644 drivers/staging/media/cec/cec-core.c create mode 100644 drivers/staging/media/cec/cec-priv.h create mode 100644 include/media/cec.h (limited to 'include') diff --git a/drivers/staging/media/cec/cec-core.c b/drivers/staging/media/cec/cec-core.c new file mode 100644 index 000000000000..61a1e69a902a --- /dev/null +++ b/drivers/staging/media/cec/cec-core.c @@ -0,0 +1,409 @@ +/* + * cec-core.c - HDMI Consumer Electronics Control framework - Core + * + * Copyright 2016 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cec-priv.h" + +#define CEC_NUM_DEVICES 256 +#define CEC_NAME "cec" + +int cec_debug; +module_param_named(debug, cec_debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); + +static dev_t cec_dev_t; + +/* Active devices */ +static DEFINE_MUTEX(cec_devnode_lock); +static DECLARE_BITMAP(cec_devnode_nums, CEC_NUM_DEVICES); + +static struct dentry *top_cec_dir; + +/* dev to cec_devnode */ +#define to_cec_devnode(cd) container_of(cd, struct cec_devnode, dev) + +int cec_get_device(struct cec_devnode *devnode) +{ + /* + * Check if the cec device is available. This needs to be done with + * the cec_devnode_lock held to prevent an open/unregister race: + * without the lock, the device could be unregistered and freed between + * the devnode->registered check and get_device() calls, leading to + * a crash. + */ + mutex_lock(&cec_devnode_lock); + /* + * return ENXIO if the cec device has been removed + * already or if it is not registered anymore. + */ + if (!devnode->registered) { + mutex_unlock(&cec_devnode_lock); + return -ENXIO; + } + /* and increase the device refcount */ + get_device(&devnode->dev); + mutex_unlock(&cec_devnode_lock); + return 0; +} + +void cec_put_device(struct cec_devnode *devnode) +{ + mutex_lock(&cec_devnode_lock); + put_device(&devnode->dev); + mutex_unlock(&cec_devnode_lock); +} + +/* Called when the last user of the cec device exits. */ +static void cec_devnode_release(struct device *cd) +{ + struct cec_devnode *devnode = to_cec_devnode(cd); + + mutex_lock(&cec_devnode_lock); + + /* Mark device node number as free */ + clear_bit(devnode->minor, cec_devnode_nums); + + mutex_unlock(&cec_devnode_lock); + cec_delete_adapter(to_cec_adapter(devnode)); +} + +static struct bus_type cec_bus_type = { + .name = CEC_NAME, +}; + +/* + * Register a cec device node + * + * The registration code assigns minor numbers and registers the new device node + * with the kernel. An error is returned if no free minor number can be found, + * or if the registration of the device node fails. + * + * Zero is returned on success. + * + * Note that if the cec_devnode_register call fails, the release() callback of + * the cec_devnode structure is *not* called, so the caller is responsible for + * freeing any data. + */ +static int __must_check cec_devnode_register(struct cec_devnode *devnode, + struct module *owner) +{ + int minor; + int ret; + + /* Initialization */ + INIT_LIST_HEAD(&devnode->fhs); + mutex_init(&devnode->fhs_lock); + + /* Part 1: Find a free minor number */ + mutex_lock(&cec_devnode_lock); + minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0); + if (minor == CEC_NUM_DEVICES) { + mutex_unlock(&cec_devnode_lock); + pr_err("could not get a free minor\n"); + return -ENFILE; + } + + set_bit(minor, cec_devnode_nums); + mutex_unlock(&cec_devnode_lock); + + devnode->minor = minor; + devnode->dev.bus = &cec_bus_type; + devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor); + devnode->dev.release = cec_devnode_release; + devnode->dev.parent = devnode->parent; + dev_set_name(&devnode->dev, "cec%d", devnode->minor); + device_initialize(&devnode->dev); + + /* Part 2: Initialize and register the character device */ + cdev_init(&devnode->cdev, &cec_devnode_fops); + devnode->cdev.kobj.parent = &devnode->dev.kobj; + devnode->cdev.owner = owner; + + ret = cdev_add(&devnode->cdev, devnode->dev.devt, 1); + if (ret < 0) { + pr_err("%s: cdev_add failed\n", __func__); + goto clr_bit; + } + + ret = device_add(&devnode->dev); + if (ret) + goto cdev_del; + + devnode->registered = true; + return 0; + +cdev_del: + cdev_del(&devnode->cdev); +clr_bit: + clear_bit(devnode->minor, cec_devnode_nums); + return ret; +} + +/* + * Unregister a cec device node + * + * This unregisters the passed device. Future open calls will be met with + * errors. + * + * This function can safely be called if the device node has never been + * registered or has already been unregistered. + */ +static void cec_devnode_unregister(struct cec_devnode *devnode) +{ + struct cec_fh *fh; + + /* Check if devnode was never registered or already unregistered */ + if (!devnode->registered || devnode->unregistered) + return; + + mutex_lock(&devnode->fhs_lock); + list_for_each_entry(fh, &devnode->fhs, list) + wake_up_interruptible(&fh->wait); + mutex_unlock(&devnode->fhs_lock); + + devnode->registered = false; + devnode->unregistered = true; + device_del(&devnode->dev); + cdev_del(&devnode->cdev); + put_device(&devnode->dev); +} + +struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, + void *priv, const char *name, u32 caps, + u8 available_las, struct device *parent) +{ + struct cec_adapter *adap; + int res; + + if (WARN_ON(!parent)) + return ERR_PTR(-EINVAL); + if (WARN_ON(!caps)) + return ERR_PTR(-EINVAL); + if (WARN_ON(!ops)) + return ERR_PTR(-EINVAL); + if (WARN_ON(!available_las || available_las > CEC_MAX_LOG_ADDRS)) + return ERR_PTR(-EINVAL); + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (!adap) + return ERR_PTR(-ENOMEM); + adap->owner = parent->driver->owner; + adap->devnode.parent = parent; + strlcpy(adap->name, name, sizeof(adap->name)); + adap->phys_addr = CEC_PHYS_ADDR_INVALID; + adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; + adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; + adap->capabilities = caps; + adap->available_log_addrs = available_las; + adap->sequence = 0; + adap->ops = ops; + adap->priv = priv; + memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); + mutex_init(&adap->lock); + INIT_LIST_HEAD(&adap->transmit_queue); + INIT_LIST_HEAD(&adap->wait_queue); + init_waitqueue_head(&adap->kthread_waitq); + + adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); + if (IS_ERR(adap->kthread)) { + pr_err("cec-%s: kernel_thread() failed\n", name); + res = PTR_ERR(adap->kthread); + kfree(adap); + return ERR_PTR(res); + } + + if (!(caps & CEC_CAP_RC)) + return adap; + +#if IS_ENABLED(CONFIG_RC_CORE) + /* Prepare the RC input device */ + adap->rc = rc_allocate_device(); + if (!adap->rc) { + pr_err("cec-%s: failed to allocate memory for rc_dev\n", + name); + kthread_stop(adap->kthread); + kfree(adap); + return ERR_PTR(-ENOMEM); + } + + snprintf(adap->input_name, sizeof(adap->input_name), + "RC for %s", name); + snprintf(adap->input_phys, sizeof(adap->input_phys), + "%s/input0", name); + + adap->rc->input_name = adap->input_name; + adap->rc->input_phys = adap->input_phys; + adap->rc->input_id.bustype = BUS_CEC; + adap->rc->input_id.vendor = 0; + adap->rc->input_id.product = 0; + adap->rc->input_id.version = 1; + adap->rc->dev.parent = parent; + adap->rc->driver_type = RC_DRIVER_SCANCODE; + adap->rc->driver_name = CEC_NAME; + adap->rc->allowed_protocols = RC_BIT_CEC; + adap->rc->priv = adap; + adap->rc->map_name = RC_MAP_CEC; + adap->rc->timeout = MS_TO_NS(100); +#else + adap->capabilities &= ~CEC_CAP_RC; +#endif + return adap; +} +EXPORT_SYMBOL_GPL(cec_allocate_adapter); + +int cec_register_adapter(struct cec_adapter *adap) +{ + int res; + + if (IS_ERR_OR_NULL(adap)) + return 0; + +#if IS_ENABLED(CONFIG_RC_CORE) + if (adap->capabilities & CEC_CAP_RC) { + res = rc_register_device(adap->rc); + + if (res) { + pr_err("cec-%s: failed to prepare input device\n", + adap->name); + rc_free_device(adap->rc); + adap->rc = NULL; + return res; + } + } +#endif + + res = cec_devnode_register(&adap->devnode, adap->owner); + if (res) { +#if IS_ENABLED(CONFIG_RC_CORE) + /* Note: rc_unregister also calls rc_free */ + rc_unregister_device(adap->rc); + adap->rc = NULL; +#endif + return res; + } + + dev_set_drvdata(&adap->devnode.dev, adap); +#ifdef CONFIG_MEDIA_CEC_DEBUG + if (!top_cec_dir) + return 0; + + adap->cec_dir = debugfs_create_dir(dev_name(&adap->devnode.dev), top_cec_dir); + if (IS_ERR_OR_NULL(adap->cec_dir)) { + pr_warn("cec-%s: Failed to create debugfs dir\n", adap->name); + return 0; + } + adap->status_file = debugfs_create_devm_seqfile(&adap->devnode.dev, + "status", adap->cec_dir, cec_adap_status); + if (IS_ERR_OR_NULL(adap->status_file)) { + pr_warn("cec-%s: Failed to create status file\n", adap->name); + debugfs_remove_recursive(adap->cec_dir); + adap->cec_dir = NULL; + } +#endif + return 0; +} +EXPORT_SYMBOL_GPL(cec_register_adapter); + +void cec_unregister_adapter(struct cec_adapter *adap) +{ + if (IS_ERR_OR_NULL(adap)) + return; + +#if IS_ENABLED(CONFIG_RC_CORE) + /* Note: rc_unregister also calls rc_free */ + rc_unregister_device(adap->rc); + adap->rc = NULL; +#endif + debugfs_remove_recursive(adap->cec_dir); + cec_devnode_unregister(&adap->devnode); +} +EXPORT_SYMBOL_GPL(cec_unregister_adapter); + +void cec_delete_adapter(struct cec_adapter *adap) +{ + if (IS_ERR_OR_NULL(adap)) + return; + mutex_lock(&adap->lock); + __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); + mutex_unlock(&adap->lock); + kthread_stop(adap->kthread); + if (adap->kthread_config) + kthread_stop(adap->kthread_config); +#if IS_ENABLED(CONFIG_RC_CORE) + if (adap->rc) + rc_free_device(adap->rc); +#endif + kfree(adap); +} +EXPORT_SYMBOL_GPL(cec_delete_adapter); + +/* + * Initialise cec for linux + */ +static int __init cec_devnode_init(void) +{ + int ret; + + pr_info("Linux cec interface: v0.10\n"); + ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, + CEC_NAME); + if (ret < 0) { + pr_warn("cec: unable to allocate major\n"); + return ret; + } + +#ifdef CONFIG_MEDIA_CEC_DEBUG + top_cec_dir = debugfs_create_dir("cec", NULL); + if (IS_ERR_OR_NULL(top_cec_dir)) { + pr_warn("cec: Failed to create debugfs cec dir\n"); + top_cec_dir = NULL; + } +#endif + + ret = bus_register(&cec_bus_type); + if (ret < 0) { + unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); + pr_warn("cec: bus_register failed\n"); + return -EIO; + } + + return 0; +} + +static void __exit cec_devnode_exit(void) +{ + debugfs_remove_recursive(top_cec_dir); + bus_unregister(&cec_bus_type); + unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); +} + +subsys_initcall(cec_devnode_init); +module_exit(cec_devnode_exit) + +MODULE_AUTHOR("Hans Verkuil "); +MODULE_DESCRIPTION("Device node registration for cec drivers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/cec/cec-priv.h b/drivers/staging/media/cec/cec-priv.h new file mode 100644 index 000000000000..70767a7900f2 --- /dev/null +++ b/drivers/staging/media/cec/cec-priv.h @@ -0,0 +1,56 @@ +/* + * cec-priv.h - HDMI Consumer Electronics Control internal header + * + * Copyright 2016 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 _CEC_PRIV_H +#define _CEC_PRIV_H + +#include +#include + +#define dprintk(lvl, fmt, arg...) \ + do { \ + if (lvl <= cec_debug) \ + pr_info("cec-%s: " fmt, adap->name, ## arg); \ + } while (0) + +/* devnode to cec_adapter */ +#define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode) + +/* cec-core.c */ +extern int cec_debug; +int cec_get_device(struct cec_devnode *devnode); +void cec_put_device(struct cec_devnode *devnode); + +/* cec-adap.c */ +int cec_monitor_all_cnt_inc(struct cec_adapter *adap); +void cec_monitor_all_cnt_dec(struct cec_adapter *adap); +int cec_adap_status(struct seq_file *file, void *priv); +int cec_thread_func(void *_adap); +void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block); +int __cec_s_log_addrs(struct cec_adapter *adap, + struct cec_log_addrs *log_addrs, bool block); +int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, + struct cec_fh *fh, bool block); +void cec_queue_event_fh(struct cec_fh *fh, + const struct cec_event *new_ev, u64 ts); + +/* cec-api.c */ +extern const struct file_operations cec_devnode_fops; + +#endif diff --git a/include/media/cec.h b/include/media/cec.h new file mode 100644 index 000000000000..9a791c08a789 --- /dev/null +++ b/include/media/cec.h @@ -0,0 +1,232 @@ +/* + * cec - HDMI Consumer Electronics Control support header + * + * Copyright 2016 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 _MEDIA_CEC_H +#define _MEDIA_CEC_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct cec_devnode - cec device node + * @dev: cec device + * @cdev: cec character device + * @parent: parent device + * @minor: device node minor number + * @registered: the device was correctly registered + * @unregistered: the device was unregistered + * @fhs_lock: lock to control access to the filehandle list + * @fhs: the list of open filehandles (cec_fh) + * + * This structure represents a cec-related device node. + * + * The @parent is a physical device. It must be set by core or device drivers + * before registering the node. + */ +struct cec_devnode { + /* sysfs */ + struct device dev; + struct cdev cdev; + struct device *parent; + + /* device info */ + int minor; + bool registered; + bool unregistered; + struct mutex fhs_lock; + struct list_head fhs; +}; + +struct cec_adapter; +struct cec_data; + +struct cec_data { + struct list_head list; + struct list_head xfer_list; + struct cec_adapter *adap; + struct cec_msg msg; + struct cec_fh *fh; + struct delayed_work work; + struct completion c; + u8 attempts; + bool new_initiator; + bool blocking; + bool completed; +}; + +struct cec_msg_entry { + struct list_head list; + struct cec_msg msg; +}; + +#define CEC_NUM_EVENTS CEC_EVENT_LOST_MSGS + +struct cec_fh { + struct list_head list; + struct list_head xfer_list; + struct cec_adapter *adap; + u8 mode_initiator; + u8 mode_follower; + + /* Events */ + wait_queue_head_t wait; + unsigned int pending_events; + struct cec_event events[CEC_NUM_EVENTS]; + struct mutex lock; + struct list_head msgs; /* queued messages */ + unsigned int queued_msgs; +}; + +#define CEC_SIGNAL_FREE_TIME_RETRY 3 +#define CEC_SIGNAL_FREE_TIME_NEW_INITIATOR 5 +#define CEC_SIGNAL_FREE_TIME_NEXT_XFER 7 + +/* The nominal data bit period is 2.4 ms */ +#define CEC_FREE_TIME_TO_USEC(ft) ((ft) * 2400) + +struct cec_adap_ops { + /* Low-level callbacks */ + int (*adap_enable)(struct cec_adapter *adap, bool enable); + int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable); + int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr); + int (*adap_transmit)(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg); + void (*adap_status)(struct cec_adapter *adap, struct seq_file *file); + + /* High-level CEC message callback */ + int (*received)(struct cec_adapter *adap, struct cec_msg *msg); +}; + +/* + * The minimum message length you can receive (excepting poll messages) is 2. + * With a transfer rate of at most 36 bytes per second this makes 18 messages + * per second worst case. + * + * We queue at most 3 seconds worth of messages. The CEC specification requires + * that messages are replied to within a second, so 3 seconds should give more + * than enough margin. Since most messages are actually more than 2 bytes, this + * is in practice a lot more than 3 seconds. + */ +#define CEC_MAX_MSG_QUEUE_SZ (18 * 3) + +struct cec_adapter { + struct module *owner; + char name[32]; + struct cec_devnode devnode; + struct mutex lock; + struct rc_dev *rc; + + struct list_head transmit_queue; + struct list_head wait_queue; + struct cec_data *transmitting; + + struct task_struct *kthread_config; + struct completion config_completion; + + struct task_struct *kthread; + wait_queue_head_t kthread_waitq; + wait_queue_head_t waitq; + + const struct cec_adap_ops *ops; + void *priv; + u32 capabilities; + u8 available_log_addrs; + + u16 phys_addr; + bool is_configuring; + bool is_configured; + u32 monitor_all_cnt; + u32 follower_cnt; + struct cec_fh *cec_follower; + struct cec_fh *cec_initiator; + bool passthrough; + struct cec_log_addrs log_addrs; + + struct dentry *cec_dir; + struct dentry *status_file; + + u16 phys_addrs[15]; + u32 sequence; + + char input_name[32]; + char input_phys[32]; + char input_drv[32]; +}; + +static inline bool cec_has_log_addr(const struct cec_adapter *adap, u8 log_addr) +{ + return adap->log_addrs.log_addr_mask & (1 << log_addr); +} + +static inline bool cec_is_sink(const struct cec_adapter *adap) +{ + return adap->phys_addr == 0; +} + +#if IS_ENABLED(CONFIG_MEDIA_CEC) +struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, + void *priv, const char *name, u32 caps, u8 available_las, + struct device *parent); +int cec_register_adapter(struct cec_adapter *adap); +void cec_unregister_adapter(struct cec_adapter *adap); +void cec_delete_adapter(struct cec_adapter *adap); + +int cec_s_log_addrs(struct cec_adapter *adap, struct cec_log_addrs *log_addrs, + bool block); +void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, + bool block); +int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg, + bool block); + +/* Called by the adapter */ +void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, + u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt); +void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg); + +#else + +static inline int cec_register_adapter(struct cec_adapter *adap) +{ + return 0; +} + +static inline void cec_unregister_adapter(struct cec_adapter *adap) +{ +} + +static inline void cec_delete_adapter(struct cec_adapter *adap) +{ +} + +static inline void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, + bool block) +{ +} + +#endif + +#endif /* _MEDIA_CEC_H */ -- cgit v1.2.3 From 257d4eaed38c736da1654048e14ecd2b76bebf03 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 29 Jun 2015 04:55:35 -0300 Subject: [media] cec: adv7511: add cec support Add CEC support to the adv7511 driver. Signed-off-by: Hans Verkuil [k.debski@samsung.com: Merged changes from CEC Updates commit by Hans Verkuil] Signed-off-by: Kamil Debski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 8 + drivers/media/i2c/adv7511.c | 401 +++++++++++++++++++++++++++++++++++++++++++- include/media/i2c/adv7511.h | 6 +- 3 files changed, 402 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 0179d10724fe..ce9006e10a30 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -463,6 +463,7 @@ config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API select HDMI + select MEDIA_CEC_EDID ---help--- Support for the Analog Devices ADV7511 video encoder. @@ -471,6 +472,13 @@ config VIDEO_ADV7511 To compile this driver as a module, choose M here: the module will be called adv7511. +config VIDEO_ADV7511_CEC + bool "Enable Analog Devices ADV7511 CEC support" + depends on VIDEO_ADV7511 && MEDIA_CEC + ---help--- + When selected the adv7511 will support the optional + HDMI CEC feature. + config VIDEO_AD9389B tristate "Analog Devices AD9389B encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 39271c35da48..39d409f99628 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -33,6 +33,7 @@ #include #include #include +#include static int debug; module_param(debug, int, 0644); @@ -59,6 +60,8 @@ MODULE_LICENSE("GPL v2"); #define ADV7511_MIN_PIXELCLOCK 20000000 #define ADV7511_MAX_PIXELCLOCK 225000000 +#define ADV7511_MAX_ADDRS (3) + /* ********************************************************************** * @@ -90,12 +93,20 @@ struct adv7511_state { struct v4l2_ctrl_handler hdl; int chip_revision; u8 i2c_edid_addr; - u8 i2c_cec_addr; u8 i2c_pktmem_addr; + u8 i2c_cec_addr; + + struct i2c_client *i2c_cec; + struct cec_adapter *cec_adap; + u8 cec_addr[ADV7511_MAX_ADDRS]; + u8 cec_valid_addrs; + bool cec_enabled_adap; + /* Is the adv7511 powered on? */ bool power_on; /* Did we receive hotplug and rx-sense signals? */ bool have_monitor; + bool enabled_irq; /* timings from s_dv_timings */ struct v4l2_dv_timings dv_timings; u32 fmt_code; @@ -227,7 +238,7 @@ static int adv_smbus_read_i2c_block_data(struct i2c_client *client, return ret; } -static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf) +static void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf) { struct adv7511_state *state = get_adv7511_state(sd); int i; @@ -242,6 +253,34 @@ static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf) v4l2_err(sd, "%s: i2c read error\n", __func__); } +static inline int adv7511_cec_read(struct v4l2_subdev *sd, u8 reg) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + return i2c_smbus_read_byte_data(state->i2c_cec, reg); +} + +static int adv7511_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct adv7511_state *state = get_adv7511_state(sd); + int ret; + int i; + + for (i = 0; i < 3; i++) { + ret = i2c_smbus_write_byte_data(state->i2c_cec, reg, val); + if (ret == 0) + return 0; + } + v4l2_err(sd, "%s: I2C Write Problem\n", __func__); + return ret; +} + +static inline int adv7511_cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, + u8 val) +{ + return adv7511_cec_write(sd, reg, (adv7511_cec_read(sd, reg) & mask) | val); +} + static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg) { struct adv7511_state *state = get_adv7511_state(sd); @@ -425,16 +464,28 @@ static const struct v4l2_ctrl_ops adv7511_ctrl_ops = { #ifdef CONFIG_VIDEO_ADV_DEBUG static void adv7511_inv_register(struct v4l2_subdev *sd) { + struct adv7511_state *state = get_adv7511_state(sd); + v4l2_info(sd, "0x000-0x0ff: Main Map\n"); + if (state->i2c_cec) + v4l2_info(sd, "0x100-0x1ff: CEC Map\n"); } static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { + struct adv7511_state *state = get_adv7511_state(sd); + reg->size = 1; switch (reg->reg >> 8) { case 0: reg->val = adv7511_rd(sd, reg->reg & 0xff); break; + case 1: + if (state->i2c_cec) { + reg->val = adv7511_cec_read(sd, reg->reg & 0xff); + break; + } + /* fall through */ default: v4l2_info(sd, "Register %03llx not supported\n", reg->reg); adv7511_inv_register(sd); @@ -445,10 +496,18 @@ static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { + struct adv7511_state *state = get_adv7511_state(sd); + switch (reg->reg >> 8) { case 0: adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff); break; + case 1: + if (state->i2c_cec) { + adv7511_cec_write(sd, reg->reg & 0xff, reg->val & 0xff); + break; + } + /* fall through */ default: v4l2_info(sd, "Register %03llx not supported\n", reg->reg); adv7511_inv_register(sd); @@ -536,6 +595,7 @@ static int adv7511_log_status(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); struct adv7511_state_edid *edid = &state->edid; + int i; static const char * const states[] = { "in reset", @@ -605,7 +665,23 @@ static int adv7511_log_status(struct v4l2_subdev *sd) else v4l2_info(sd, "no timings set\n"); v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr); + + if (state->i2c_cec == NULL) + return 0; + v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr); + + v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ? + "enabled" : "disabled"); + if (state->cec_enabled_adap) { + for (i = 0; i < ADV7511_MAX_ADDRS; i++) { + bool is_valid = state->cec_valid_addrs & (1 << i); + + if (is_valid) + v4l2_info(sd, "CEC Logical Address: 0x%x\n", + state->cec_addr[i]); + } + } v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr); return 0; } @@ -663,15 +739,197 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on) return true; } +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) +static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct adv7511_state *state = adap->priv; + struct v4l2_subdev *sd = &state->sd; + + if (state->i2c_cec == NULL) + return -EIO; + + if (!state->cec_enabled_adap && enable) { + /* power up cec section */ + adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x01); + /* legacy mode and clear all rx buffers */ + adv7511_cec_write(sd, 0x4a, 0x07); + adv7511_cec_write(sd, 0x4a, 0); + adv7511_cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */ + /* enabled irqs: */ + /* tx: ready */ + /* tx: arbitration lost */ + /* tx: retry timeout */ + /* rx: ready 1 */ + if (state->enabled_irq) + adv7511_wr_and_or(sd, 0x95, 0xc0, 0x39); + } else if (state->cec_enabled_adap && !enable) { + if (state->enabled_irq) + adv7511_wr_and_or(sd, 0x95, 0xc0, 0x00); + /* disable address mask 1-3 */ + adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0x00); + /* power down cec section */ + adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x00); + state->cec_valid_addrs = 0; + } + state->cec_enabled_adap = enable; + return 0; +} + +static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ + struct adv7511_state *state = adap->priv; + struct v4l2_subdev *sd = &state->sd; + unsigned int i, free_idx = ADV7511_MAX_ADDRS; + + if (!state->cec_enabled_adap) + return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; + + if (addr == CEC_LOG_ADDR_INVALID) { + adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0); + state->cec_valid_addrs = 0; + return 0; + } + + for (i = 0; i < ADV7511_MAX_ADDRS; i++) { + bool is_valid = state->cec_valid_addrs & (1 << i); + + if (free_idx == ADV7511_MAX_ADDRS && !is_valid) + free_idx = i; + if (is_valid && state->cec_addr[i] == addr) + return 0; + } + if (i == ADV7511_MAX_ADDRS) { + i = free_idx; + if (i == ADV7511_MAX_ADDRS) + return -ENXIO; + } + state->cec_addr[i] = addr; + state->cec_valid_addrs |= 1 << i; + + switch (i) { + case 0: + /* enable address mask 0 */ + adv7511_cec_write_and_or(sd, 0x4b, 0xef, 0x10); + /* set address for mask 0 */ + adv7511_cec_write_and_or(sd, 0x4c, 0xf0, addr); + break; + case 1: + /* enable address mask 1 */ + adv7511_cec_write_and_or(sd, 0x4b, 0xdf, 0x20); + /* set address for mask 1 */ + adv7511_cec_write_and_or(sd, 0x4c, 0x0f, addr << 4); + break; + case 2: + /* enable address mask 2 */ + adv7511_cec_write_and_or(sd, 0x4b, 0xbf, 0x40); + /* set address for mask 1 */ + adv7511_cec_write_and_or(sd, 0x4d, 0xf0, addr); + break; + } + return 0; +} + +static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct adv7511_state *state = adap->priv; + struct v4l2_subdev *sd = &state->sd; + u8 len = msg->len; + unsigned int i; + + v4l2_dbg(1, debug, sd, "%s: len %d\n", __func__, len); + + if (len > 16) { + v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); + return -EINVAL; + } + + /* + * The number of retries is the number of attempts - 1, but retry + * at least once. It's not clear if a value of 0 is allowed, so + * let's do at least one retry. + */ + adv7511_cec_write_and_or(sd, 0x12, ~0x70, max(1, attempts - 1) << 4); + + /* blocking, clear cec tx irq status */ + adv7511_wr_and_or(sd, 0x97, 0xc7, 0x38); + + /* write data */ + for (i = 0; i < len; i++) + adv7511_cec_write(sd, i, msg->msg[i]); + + /* set length (data + header) */ + adv7511_cec_write(sd, 0x10, len); + /* start transmit, enable tx */ + adv7511_cec_write(sd, 0x11, 0x01); + return 0; +} + +static void adv_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + if ((adv7511_cec_read(sd, 0x11) & 0x01) == 0) { + v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); + return; + } + + if (tx_raw_status & 0x10) { + v4l2_dbg(1, debug, sd, + "%s: tx raw: arbitration lost\n", __func__); + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, + 1, 0, 0, 0); + return; + } + if (tx_raw_status & 0x08) { + u8 status; + u8 nack_cnt; + u8 low_drive_cnt; + + v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); + /* + * We set this status bit since this hardware performs + * retransmissions. + */ + status = CEC_TX_STATUS_MAX_RETRIES; + nack_cnt = adv7511_cec_read(sd, 0x14) & 0xf; + if (nack_cnt) + status |= CEC_TX_STATUS_NACK; + low_drive_cnt = adv7511_cec_read(sd, 0x14) >> 4; + if (low_drive_cnt) + status |= CEC_TX_STATUS_LOW_DRIVE; + cec_transmit_done(state->cec_adap, status, + 0, nack_cnt, low_drive_cnt, 0); + return; + } + if (tx_raw_status & 0x20) { + v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); + return; + } +} + +static const struct cec_adap_ops adv7511_cec_adap_ops = { + .adap_enable = adv7511_cec_adap_enable, + .adap_log_addr = adv7511_cec_adap_log_addr, + .adap_transmit = adv7511_cec_adap_transmit, +}; +#endif + /* Enable interrupts */ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) { + struct adv7511_state *state = get_adv7511_state(sd); u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT; u8 irqs_rd; int retries = 100; v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable"); + if (state->enabled_irq == enable) + return; + state->enabled_irq = enable; + /* The datasheet says that the EDID ready interrupt should be disabled if there is no hotplug. */ if (!enable) @@ -679,6 +937,9 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) else if (adv7511_have_hotplug(sd)) irqs |= MASK_ADV7511_EDID_RDY_INT; + adv7511_wr_and_or(sd, 0x95, 0xc0, + (state->cec_enabled_adap && enable) ? 0x39 : 0x00); + /* * This i2c write can fail (approx. 1 in 1000 writes). But it * is essential that this register is correct, so retry it @@ -701,20 +962,53 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { u8 irq_status; + u8 cec_irq; /* disable interrupts to prevent a race condition */ adv7511_set_isr(sd, false); irq_status = adv7511_rd(sd, 0x96); + cec_irq = adv7511_rd(sd, 0x97); /* clear detected interrupts */ adv7511_wr(sd, 0x96, irq_status); + adv7511_wr(sd, 0x97, cec_irq); - v4l2_dbg(1, debug, sd, "%s: irq 0x%x\n", __func__, irq_status); + v4l2_dbg(1, debug, sd, "%s: irq 0x%x, cec-irq 0x%x\n", __func__, + irq_status, cec_irq); if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT)) adv7511_check_monitor_present_status(sd); if (irq_status & MASK_ADV7511_EDID_RDY_INT) adv7511_check_edid_status(sd); +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) + if (cec_irq & 0x38) + adv_cec_tx_raw_status(sd, cec_irq); + + if (cec_irq & 1) { + struct adv7511_state *state = get_adv7511_state(sd); + struct cec_msg msg; + + msg.len = adv7511_cec_read(sd, 0x25) & 0x1f; + + v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__, + msg.len); + + if (msg.len > 16) + msg.len = 16; + + if (msg.len) { + u8 i; + + for (i = 0; i < msg.len; i++) + msg.msg[i] = adv7511_cec_read(sd, i + 0x15); + + adv7511_cec_write(sd, 0x4a, 1); /* toggle to re-enable rx 1 */ + adv7511_cec_write(sd, 0x4a, 0); + cec_received_msg(state->cec_adap, &msg); + } + } +#endif + /* enable interrupts */ adv7511_set_isr(sd, true); @@ -1183,6 +1477,8 @@ static void adv7511_notify_no_edid(struct v4l2_subdev *sd) /* We failed to read the EDID, so send an event for this. */ ed.present = false; ed.segment = adv7511_rd(sd, 0xc4); + ed.phys_addr = CEC_PHYS_ADDR_INVALID; + cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0); } @@ -1406,13 +1702,16 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments); state->edid.complete = true; - + ed.phys_addr = cec_get_edid_phys_addr(state->edid.data, + state->edid.segments * 256, + NULL); /* report when we have all segments but report only for segment 0 */ ed.present = true; ed.segment = 0; state->edid_detect_counter++; + cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); return ed.present; } @@ -1420,17 +1719,43 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) return false; } +static int adv7511_registered(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + int err; + + err = cec_register_adapter(state->cec_adap); + if (err) + cec_delete_adapter(state->cec_adap); + return err; +} + +static void adv7511_unregistered(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + cec_unregister_adapter(state->cec_adap); +} + +static const struct v4l2_subdev_internal_ops adv7511_int_ops = { + .registered = adv7511_registered, + .unregistered = adv7511_unregistered, +}; + /* ----------------------------------------------------------------------- */ /* Setup ADV7511 */ static void adv7511_init_setup(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); struct adv7511_state_edid *edid = &state->edid; + u32 cec_clk = state->pdata.cec_clk; + u8 ratio; v4l2_dbg(1, debug, sd, "%s\n", __func__); /* clear all interrupts */ adv7511_wr(sd, 0x96, 0xff); + adv7511_wr(sd, 0x97, 0xff); /* * Stop HPD from resetting a lot of registers. * It might leave the chip in a partly un-initialized state, @@ -1442,6 +1767,25 @@ static void adv7511_init_setup(struct v4l2_subdev *sd) adv7511_set_isr(sd, false); adv7511_s_stream(sd, false); adv7511_s_audio_stream(sd, false); + + if (state->i2c_cec == NULL) + return; + + v4l2_dbg(1, debug, sd, "%s: cec_clk %d\n", __func__, cec_clk); + + /* cec soft reset */ + adv7511_cec_write(sd, 0x50, 0x01); + adv7511_cec_write(sd, 0x50, 0x00); + + /* legacy mode */ + adv7511_cec_write(sd, 0x4a, 0x00); + + if (cec_clk % 750000 != 0) + v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n", + __func__, cec_clk); + + ratio = (cec_clk / 750000) - 1; + adv7511_cec_write(sd, 0x4e, ratio << 2); } static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -1476,6 +1820,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * client->addr << 1); v4l2_i2c_subdev_init(sd, client, &adv7511_ops); + sd->internal_ops = &adv7511_int_ops; hdl = &state->hdl; v4l2_ctrl_handler_init(hdl, 10); @@ -1516,26 +1861,47 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * chip_id[0] = adv7511_rd(sd, 0xf5); chip_id[1] = adv7511_rd(sd, 0xf6); if (chip_id[0] != 0x75 || chip_id[1] != 0x11) { - v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], chip_id[1]); + v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], + chip_id[1]); err = -EIO; goto err_entity; } - state->i2c_edid = i2c_new_dummy(client->adapter, state->i2c_edid_addr >> 1); + state->i2c_edid = i2c_new_dummy(client->adapter, + state->i2c_edid_addr >> 1); if (state->i2c_edid == NULL) { v4l2_err(sd, "failed to register edid i2c client\n"); err = -ENOMEM; goto err_entity; } + adv7511_wr(sd, 0xe1, state->i2c_cec_addr); + if (state->pdata.cec_clk < 3000000 || + state->pdata.cec_clk > 100000000) { + v4l2_err(sd, "%s: cec_clk %u outside range, disabling cec\n", + __func__, state->pdata.cec_clk); + state->pdata.cec_clk = 0; + } + + if (state->pdata.cec_clk) { + state->i2c_cec = i2c_new_dummy(client->adapter, + state->i2c_cec_addr >> 1); + if (state->i2c_cec == NULL) { + v4l2_err(sd, "failed to register cec i2c client\n"); + goto err_unreg_edid; + } + adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ + } else { + adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ + } + state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); if (state->i2c_pktmem == NULL) { v4l2_err(sd, "failed to register pktmem i2c client\n"); err = -ENOMEM; - goto err_unreg_edid; + goto err_unreg_cec; } - adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ state->work_queue = create_singlethread_workqueue(sd->name); if (state->work_queue == NULL) { v4l2_err(sd, "could not create workqueue\n"); @@ -1546,6 +1912,19 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler); adv7511_init_setup(sd); + +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) + state->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops, + state, dev_name(&client->dev), CEC_CAP_TRANSMIT | + CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | CEC_CAP_RC, + ADV7511_MAX_ADDRS, &client->dev); + err = PTR_ERR_OR_ZERO(state->cec_adap); + if (err) { + destroy_workqueue(state->work_queue); + goto err_unreg_pktmem; + } +#endif + adv7511_set_isr(sd, true); adv7511_check_monitor_present_status(sd); @@ -1555,6 +1934,9 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * err_unreg_pktmem: i2c_unregister_device(state->i2c_pktmem); +err_unreg_cec: + if (state->i2c_cec) + i2c_unregister_device(state->i2c_cec); err_unreg_edid: i2c_unregister_device(state->i2c_edid); err_entity: @@ -1576,9 +1958,12 @@ static int adv7511_remove(struct i2c_client *client) v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); + adv7511_set_isr(sd, false); adv7511_init_setup(sd); cancel_delayed_work(&state->edid_handler); i2c_unregister_device(state->i2c_edid); + if (state->i2c_cec) + i2c_unregister_device(state->i2c_cec); i2c_unregister_device(state->i2c_pktmem); destroy_workqueue(state->work_queue); v4l2_device_unregister_subdev(sd); diff --git a/include/media/i2c/adv7511.h b/include/media/i2c/adv7511.h index d83b91d80764..61c3d711cc69 100644 --- a/include/media/i2c/adv7511.h +++ b/include/media/i2c/adv7511.h @@ -32,11 +32,7 @@ struct adv7511_monitor_detect { struct adv7511_edid_detect { int present; int segment; -}; - -struct adv7511_cec_arg { - void *arg; - u32 f_flags; + uint16_t phys_addr; }; struct adv7511_platform_data { -- cgit v1.2.3 From 79c8d083e226fbfc20d9e801352fccfa7b08a8b3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 15 Jun 2016 20:27:58 -0300 Subject: [media] videodev2.h: Group YUV 3 planes formats together The formats are interleaved with the YUV packed and miscellaneous formats, making the result confusing especially with the YUV444 format being packed and not planar like YUV410 or YUV420. Move them to their own group as the 2 planes or 3 non-contiguous planes formats to clarify the header. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 8f951917be74..50ff346c4118 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -504,22 +504,16 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_UV8 v4l2_fourcc('U', 'V', '8', ' ') /* 8 UV 4:4 */ /* Luminance+Chrominance formats */ -#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */ -#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ #define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */ -#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */ -#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */ #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') /* 12 YUV 4:1:1 */ #define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') /* 16 xxxxyyyy uuuuvvvv */ #define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y', 'U', 'V', 'O') /* 16 YUV-5-5-5 */ #define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y', 'U', 'V', 'P') /* 16 YUV-5-6-5 */ #define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y', 'U', 'V', '4') /* 32 YUV-8-8-8-8 */ -#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ -#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */ #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ #define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */ @@ -540,6 +534,14 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ #define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 macroblocks */ +/* three planes - Y Cb, Cr */ +#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ +#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */ +#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */ +#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ +#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ +#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */ + /* three non contiguous planes - Y, Cb, Cr */ #define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ #define V4L2_PIX_FMT_YVU420M v4l2_fourcc('Y', 'M', '2', '1') /* 12 YVU420 planar */ -- cgit v1.2.3 From ab46f6d24bf57ddac0f5abe2f546a78af57b476c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 15 Jun 2016 20:35:36 -0300 Subject: [media] videodev2.h: Fix V4L2_PIX_FMT_YUV411P description YUV 4:1:1 uses 12 bits per pixel on average, not 16. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 50ff346c4118..724f43e69d03 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -537,7 +537,7 @@ struct v4l2_pix_format { /* three planes - Y Cb, Cr */ #define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */ -#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */ +#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 12 YVU411 planar */ #define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */ -- cgit v1.2.3 From 1179aab13db3c6251484afe492c8dbd869ca8b05 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 15 Feb 2016 22:00:30 -0200 Subject: [media] media: Add video processing entity functions Add composer, pixel formatter, pixel encoding converter and scaler functions. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/media-types.xml | 55 +++++++++++++++++++++++++ include/uapi/linux/media.h | 9 ++++ 2 files changed, 64 insertions(+) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/media-types.xml b/Documentation/DocBook/media/v4l/media-types.xml index 5e3f20fdcf17..60fe841f8846 100644 --- a/Documentation/DocBook/media/v4l/media-types.xml +++ b/Documentation/DocBook/media/v4l/media-types.xml @@ -121,6 +121,61 @@ MEDIA_ENT_F_AUDIO_MIXER Audio Mixer Function Entity. + + MEDIA_ENT_F_PROC_VIDEO_COMPOSER + Video composer (blender). An entity capable of video + composing must have at least two sink pads and one source + pad, and composes input video frames onto output video + frames. Composition can be performed using alpha blending, + color keying, raster operations (ROP), stitching or any other + means. + + + + MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER + Video pixel formatter. An entity capable of pixel formatting + must have at least one sink pad and one source pad. Read + pixel formatters read pixels from memory and perform a subset + of unpacking, cropping, color keying, alpha multiplication + and pixel encoding conversion. Write pixel formatters perform + a subset of dithering, pixel encoding conversion and packing + and write pixels to memory. + + + + MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV + Video pixel encoding converter. An entity capable of pixel + enconding conversion must have at least one sink pad and one + source pad, and convert the encoding of pixels received on + its sink pad(s) to a different encoding output on its source + pad(s). Pixel encoding conversion includes but isn't limited + to RGB to/from HSV, RGB to/from YUV and CFA (Bayer) to RGB + conversions. + + + + MEDIA_ENT_F_PROC_VIDEO_LUT + Video look-up table. An entity capable of video lookup table + processing must have one sink pad and one source pad. It uses + the values of the pixels received on its sink pad to look up + entries in internal tables and output them on its source pad. + The lookup processing can be performed on all components + separately or combine them for multi-dimensional table + lookups. + + + + MEDIA_ENT_F_PROC_VIDEO_SCALER + Video scaler. An entity capable of video scaling must have + at least one sink pad and one source pad, and scale the + video frame(s) received on its sink pad(s) to a different + resolution output on its source pad(s). The range of + supported scaling ratios is entity-specific and can differ + between the horizontal and vertical directions (in particular + scaling can be supported in one direction only). Binning and + skipping are considered as scaling. + + diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index df59edee25d1..3136686c4bd0 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -94,6 +94,15 @@ struct media_device_info { #define MEDIA_ENT_F_AUDIO_PLAYBACK (MEDIA_ENT_F_BASE + 0x03002) #define MEDIA_ENT_F_AUDIO_MIXER (MEDIA_ENT_F_BASE + 0x03003) +/* + * Processing entities + */ +#define MEDIA_ENT_F_PROC_VIDEO_COMPOSER (MEDIA_ENT_F_BASE + 0x4001) +#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER (MEDIA_ENT_F_BASE + 0x4002) +#define MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV (MEDIA_ENT_F_BASE + 0x4003) +#define MEDIA_ENT_F_PROC_VIDEO_LUT (MEDIA_ENT_F_BASE + 0x4004) +#define MEDIA_ENT_F_PROC_VIDEO_SCALER (MEDIA_ENT_F_BASE + 0x4005) + /* * Connectors */ -- cgit v1.2.3 From eaa0b96bbb6586a95e66d3dedd974313d7b0d94f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 1 Mar 2016 21:12:27 -0300 Subject: [media] media: Add video statistics computation functions The video statistics function describes entities such as video histogram engines or 3A statistics engines. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/media-types.xml | 9 +++++++++ include/uapi/linux/media.h | 1 + 2 files changed, 10 insertions(+) (limited to 'include') diff --git a/Documentation/DocBook/media/v4l/media-types.xml b/Documentation/DocBook/media/v4l/media-types.xml index 60fe841f8846..95aa1f9c836a 100644 --- a/Documentation/DocBook/media/v4l/media-types.xml +++ b/Documentation/DocBook/media/v4l/media-types.xml @@ -176,6 +176,15 @@ skipping are considered as scaling. + + MEDIA_ENT_F_PROC_VIDEO_STATISTICS + Video statistics computation (histogram, 3A, ...). An entity + capable of statistics computation must have one sink pad and + one source pad. It computes statistics over the frames + received on its sink pad and outputs the statistics data on + its source pad. + + diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index 3136686c4bd0..7acf0f634f70 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -102,6 +102,7 @@ struct media_device_info { #define MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV (MEDIA_ENT_F_BASE + 0x4003) #define MEDIA_ENT_F_PROC_VIDEO_LUT (MEDIA_ENT_F_BASE + 0x4004) #define MEDIA_ENT_F_PROC_VIDEO_SCALER (MEDIA_ENT_F_BASE + 0x4005) +#define MEDIA_ENT_F_PROC_VIDEO_STATISTICS (MEDIA_ENT_F_BASE + 0x4006) /* * Connectors -- cgit v1.2.3 From 42e89bed23000c0bf985a741422ef943df0ee1e9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 13 May 2016 13:52:11 -0300 Subject: [media] v4l: vsp1: lut: Expose configuration through a control Replace the custom ioctl with a V4L2 control in order to standardize the API. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_lut.c | 76 +++++++++++++++++++++++----------- drivers/media/platform/vsp1/vsp1_lut.h | 6 +-- include/uapi/linux/vsp1.h | 34 --------------- 3 files changed, 54 insertions(+), 62 deletions(-) delete mode 100644 include/uapi/linux/vsp1.h (limited to 'include') diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 4a4724965de1..db8f01dbab84 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -13,7 +13,6 @@ #include #include -#include #include @@ -35,43 +34,60 @@ static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl, } /* ----------------------------------------------------------------------------- - * V4L2 Subdevice Core Operations + * Controls */ -static int lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config) +#define V4L2_CID_VSP1_LUT_TABLE (V4L2_CID_USER_BASE | 0x1001) + +static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl) { struct vsp1_dl_body *dlb; unsigned int i; - dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, ARRAY_SIZE(config->lut)); + dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, 256); if (!dlb) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(config->lut); ++i) + for (i = 0; i < 256; ++i) vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i, - config->lut[i]); + ctrl->p_new.p_u32[i]); - mutex_lock(&lut->lock); swap(lut->lut, dlb); - mutex_unlock(&lut->lock); vsp1_dl_fragment_free(dlb); return 0; } -static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) +static int lut_s_ctrl(struct v4l2_ctrl *ctrl) { - struct vsp1_lut *lut = to_lut(subdev); - - switch (cmd) { - case VIDIOC_VSP1_LUT_CONFIG: - return lut_set_table(lut, arg); + struct vsp1_lut *lut = + container_of(ctrl->handler, struct vsp1_lut, ctrls); - default: - return -ENOIOCTLCMD; + switch (ctrl->id) { + case V4L2_CID_VSP1_LUT_TABLE: + lut_set_table(lut, ctrl); + break; } + + return 0; } +static const struct v4l2_ctrl_ops lut_ctrl_ops = { + .s_ctrl = lut_s_ctrl, +}; + +static const struct v4l2_ctrl_config lut_table_control = { + .ops = &lut_ctrl_ops, + .id = V4L2_CID_VSP1_LUT_TABLE, + .name = "Look-Up Table", + .type = V4L2_CTRL_TYPE_U32, + .min = 0x00000000, + .max = 0x00ffffff, + .step = 1, + .def = 0, + .dims = { 256}, +}; + /* ----------------------------------------------------------------------------- * V4L2 Subdevice Pad Operations */ @@ -147,10 +163,6 @@ static int lut_set_format(struct v4l2_subdev *subdev, * V4L2 Subdevice Operations */ -static const struct v4l2_subdev_core_ops lut_core_ops = { - .ioctl = lut_ioctl, -}; - static const struct v4l2_subdev_pad_ops lut_pad_ops = { .init_cfg = vsp1_entity_init_cfg, .enum_mbus_code = lut_enum_mbus_code, @@ -160,7 +172,6 @@ static const struct v4l2_subdev_pad_ops lut_pad_ops = { }; static const struct v4l2_subdev_ops lut_ops = { - .core = &lut_core_ops, .pad = &lut_pad_ops, }; @@ -176,12 +187,14 @@ static void lut_configure(struct vsp1_entity *entity, vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); - mutex_lock(&lut->lock); + mutex_lock(lut->ctrls.lock); + if (lut->lut) { vsp1_dl_list_add_fragment(dl, lut->lut); lut->lut = NULL; } - mutex_unlock(&lut->lock); + + mutex_unlock(lut->ctrls.lock); } static const struct vsp1_entity_operations lut_entity_ops = { @@ -201,8 +214,6 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) if (lut == NULL) return ERR_PTR(-ENOMEM); - mutex_init(&lut->lock); - lut->entity.ops = &lut_entity_ops; lut->entity.type = VSP1_ENTITY_LUT; @@ -211,5 +222,20 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) if (ret < 0) return ERR_PTR(ret); + /* Initialize the control handler. */ + v4l2_ctrl_handler_init(&lut->ctrls, 1); + v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL); + + lut->entity.subdev.ctrl_handler = &lut->ctrls; + + if (lut->ctrls.error) { + dev_err(vsp1->dev, "lut: failed to initialize controls\n"); + ret = lut->ctrls.error; + vsp1_entity_destroy(&lut->entity); + return ERR_PTR(ret); + } + + v4l2_ctrl_handler_setup(&lut->ctrls); + return lut; } diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h index cef874f22b6a..021898fc0ce5 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.h +++ b/drivers/media/platform/vsp1/vsp1_lut.h @@ -13,9 +13,8 @@ #ifndef __VSP1_LUT_H__ #define __VSP1_LUT_H__ -#include - #include +#include #include #include "vsp1_entity.h" @@ -28,7 +27,8 @@ struct vsp1_device; struct vsp1_lut { struct vsp1_entity entity; - struct mutex lock; + struct v4l2_ctrl_handler ctrls; + struct vsp1_dl_body *lut; }; diff --git a/include/uapi/linux/vsp1.h b/include/uapi/linux/vsp1.h deleted file mode 100644 index 9a823696d816..000000000000 --- a/include/uapi/linux/vsp1.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * vsp1.h - * - * Renesas R-Car VSP1 - User-space API - * - * Copyright (C) 2013 Renesas Corporation - * - * Contacts: Laurent Pinchart - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __VSP1_USER_H__ -#define __VSP1_USER_H__ - -#include -#include - -/* - * Private IOCTLs - * - * VIDIOC_VSP1_LUT_CONFIG - Configure the lookup table - */ - -#define VIDIOC_VSP1_LUT_CONFIG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config) - -struct vsp1_lut_config { - __u32 lut[256]; -}; - -#endif /* __VSP1_USER_H__ */ -- cgit v1.2.3 From d16e832da23edff951015f108525ef31ae8dea37 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Apr 2016 09:15:05 -0300 Subject: [media] vb2: move dma_attrs to vb2_queue Make the dma attributes struct part of vb2_queue. This greatly simplifies the remainder of the patch series since the dma_contig alloc context is now (as before) just a struct device pointer. Signed-off-by: Hans Verkuil Reviewed-by: Laurent Pinchart Cc: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 2 +- drivers/media/v4l2-core/videobuf2-dma-contig.c | 16 +++++++--------- drivers/media/v4l2-core/videobuf2-dma-sg.c | 5 +++-- drivers/media/v4l2-core/videobuf2-vmalloc.c | 5 +++-- include/media/videobuf2-core.h | 7 ++++--- include/media/videobuf2-dma-contig.h | 9 +-------- 6 files changed, 19 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 633fc1ab1d7a..36f4392df571 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -207,7 +207,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) unsigned long size = PAGE_ALIGN(vb->planes[plane].length); mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane], - size, dma_dir, q->gfp_flags); + q->dma_attrs, size, dma_dir, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index e3e47ace7daf..a7825c62ad88 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -23,7 +23,6 @@ struct vb2_dc_conf { struct device *dev; - struct dma_attrs attrs; }; struct vb2_dc_buf { @@ -140,8 +139,9 @@ static void vb2_dc_put(void *buf_priv) kfree(buf); } -static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, - enum dma_data_direction dma_dir, gfp_t gfp_flags) +static void *vb2_dc_alloc(void *alloc_ctx, const struct dma_attrs *attrs, + unsigned long size, enum dma_data_direction dma_dir, + gfp_t gfp_flags) { struct vb2_dc_conf *conf = alloc_ctx; struct device *dev = conf->dev; @@ -151,7 +151,8 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, if (!buf) return ERR_PTR(-ENOMEM); - buf->attrs = conf->attrs; + if (attrs) + buf->attrs = *attrs; buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr, GFP_KERNEL | gfp_flags, &buf->attrs); if (!buf->cookie) { @@ -729,8 +730,7 @@ const struct vb2_mem_ops vb2_dma_contig_memops = { }; EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); -void *vb2_dma_contig_init_ctx_attrs(struct device *dev, - struct dma_attrs *attrs) +void *vb2_dma_contig_init_ctx(struct device *dev) { struct vb2_dc_conf *conf; @@ -739,12 +739,10 @@ void *vb2_dma_contig_init_ctx_attrs(struct device *dev, return ERR_PTR(-ENOMEM); conf->dev = dev; - if (attrs) - conf->attrs = *attrs; return conf; } -EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx_attrs); +EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx); void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) { diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 9985c89f0513..e7153f708ade 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -99,8 +99,9 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf, return 0; } -static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, - enum dma_data_direction dma_dir, gfp_t gfp_flags) +static void *vb2_dma_sg_alloc(void *alloc_ctx, const struct dma_attrs *dma_attrs, + unsigned long size, enum dma_data_direction dma_dir, + gfp_t gfp_flags) { struct vb2_dma_sg_conf *conf = alloc_ctx; struct vb2_dma_sg_buf *buf; diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index 1c302743a1fd..fb94c80e9aa8 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -33,8 +33,9 @@ struct vb2_vmalloc_buf { static void vb2_vmalloc_put(void *buf_priv); -static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size, - enum dma_data_direction dma_dir, gfp_t gfp_flags) +static void *vb2_vmalloc_alloc(void *alloc_ctx, const struct dma_attrs *attrs, + unsigned long size, enum dma_data_direction dma_dir, + gfp_t gfp_flags) { struct vb2_vmalloc_buf *buf; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 88e3ab496e8f..444ef3b9d39f 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -27,7 +27,6 @@ enum vb2_memory { VB2_MEMORY_DMABUF = 4, }; -struct vb2_alloc_ctx; struct vb2_fileio_data; struct vb2_threadio_data; @@ -93,8 +92,8 @@ struct vb2_threadio_data; * unmap_dmabuf. */ struct vb2_mem_ops { - void *(*alloc)(void *alloc_ctx, unsigned long size, - enum dma_data_direction dma_dir, + void *(*alloc)(void *alloc_ctx, const struct dma_attrs *attrs, + unsigned long size, enum dma_data_direction dma_dir, gfp_t gfp_flags); void (*put)(void *buf_priv); struct dma_buf *(*get_dmabuf)(void *buf_priv, unsigned long flags); @@ -401,6 +400,7 @@ struct vb2_buf_ops { * caller. For example, for V4L2, it should match * the V4L2_BUF_TYPE_* in include/uapi/linux/videodev2.h * @io_modes: supported io methods (see vb2_io_modes enum) + * @dma_attrs: DMA attributes to use for the DMA. May be NULL. * @fileio_read_once: report EOF after reading the first buffer * @fileio_write_immediately: queue buffer after each write() call * @allow_zero_bytesused: allow bytesused == 0 to be passed to the driver @@ -467,6 +467,7 @@ struct vb2_buf_ops { struct vb2_queue { unsigned int type; unsigned int io_modes; + const struct dma_attrs *dma_attrs; unsigned fileio_read_once:1; unsigned fileio_write_immediately:1; unsigned allow_zero_bytesused:1; diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index f7dc8401817e..5bdd4a4072e5 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -26,14 +26,7 @@ vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) return *addr; } -void *vb2_dma_contig_init_ctx_attrs(struct device *dev, - struct dma_attrs *attrs); - -static inline void *vb2_dma_contig_init_ctx(struct device *dev) -{ - return vb2_dma_contig_init_ctx_attrs(dev, NULL); -} - +void *vb2_dma_contig_init_ctx(struct device *dev); void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); void vb2_dma_contig_clear_max_seg_size(struct device *dev); -- cgit v1.2.3 From 20be7ab8dba68072b34ae2285c282290b2344339 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 16 Dec 2015 08:30:43 -0200 Subject: [media] vb2: add a dev field to use for the default allocation context The allocation context is nothing more than a per-plane device pointer to use when allocating buffers. So just provide a dev pointer in vb2_queue for that purpose and drivers can skip allocating/releasing/filling in the allocation context unless they require different per-plane device pointers as used by some Samsung SoCs. Signed-off-by: Hans Verkuil Reviewed-by: Laurent Pinchart Cc: Sakari Ailus Cc: Florian Echtler Cc: Federico Vaga Cc: "Lad, Prabhakar" Cc: Scott Jiang Acked-by: Philipp Zabel Cc: Fabien Dessenne Acked-by: Benoit Parrot Cc: Mikhail Ulyanov Cc: Guennadi Liakhovetski Cc: Jonathan Corbet Cc: Ludovic Desroches Cc: Sergei Shtylyov Cc: Kyungmin Park Cc: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 14 ++++++++------ include/media/videobuf2-core.h | 3 +++ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 36f4392df571..aabb03e406f0 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -206,7 +206,8 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) for (plane = 0; plane < vb->num_planes; ++plane) { unsigned long size = PAGE_ALIGN(vb->planes[plane].length); - mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane], + mem_priv = call_ptr_memop(vb, alloc, + q->alloc_ctx[plane] ? : &q->dev, q->dma_attrs, size, dma_dir, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; @@ -1131,9 +1132,10 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) vb->planes[plane].data_offset = 0; /* Acquire each plane's memory */ - mem_priv = call_ptr_memop(vb, get_userptr, q->alloc_ctx[plane], - planes[plane].m.userptr, - planes[plane].length, dma_dir); + mem_priv = call_ptr_memop(vb, get_userptr, + q->alloc_ctx[plane] ? : &q->dev, + planes[plane].m.userptr, + planes[plane].length, dma_dir); if (IS_ERR_OR_NULL(mem_priv)) { dprintk(1, "failed acquiring userspace " "memory for plane %d\n", plane); @@ -1256,8 +1258,8 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) /* Acquire each plane's memory */ mem_priv = call_ptr_memop(vb, attach_dmabuf, - q->alloc_ctx[plane], dbuf, planes[plane].length, - dma_dir); + q->alloc_ctx[plane] ? : &q->dev, + dbuf, planes[plane].length, dma_dir); if (IS_ERR(mem_priv)) { dprintk(1, "failed to attach dmabuf\n"); ret = PTR_ERR(mem_priv); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 444ef3b9d39f..d38668c2ea06 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -400,6 +400,8 @@ struct vb2_buf_ops { * caller. For example, for V4L2, it should match * the V4L2_BUF_TYPE_* in include/uapi/linux/videodev2.h * @io_modes: supported io methods (see vb2_io_modes enum) + * @dev: device to use for the default allocation context if the driver + * doesn't fill in the @alloc_ctx array. * @dma_attrs: DMA attributes to use for the DMA. May be NULL. * @fileio_read_once: report EOF after reading the first buffer * @fileio_write_immediately: queue buffer after each write() call @@ -467,6 +469,7 @@ struct vb2_buf_ops { struct vb2_queue { unsigned int type; unsigned int io_modes; + struct device *dev; const struct dma_attrs *dma_attrs; unsigned fileio_read_once:1; unsigned fileio_write_immediately:1; -- cgit v1.2.3 From 53ddcc683faef8c730c7162fa1ef2261a385d16d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Feb 2016 13:09:10 -0200 Subject: [media] media/platform: convert drivers to use the new vb2_queue dev field Stop using alloc_ctx and just fill in the device pointer. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Cc: Scott Jiang Acked-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/am437x/am437x-vpfe.c | 10 +--------- drivers/media/platform/am437x/am437x-vpfe.h | 2 -- drivers/media/platform/blackfin/bfin_capture.c | 15 ++------------- drivers/media/platform/coda/coda-common.c | 16 ++-------------- drivers/media/platform/coda/coda.h | 1 - drivers/media/platform/davinci/vpbe_display.c | 12 +----------- drivers/media/platform/davinci/vpif_capture.c | 11 +---------- drivers/media/platform/davinci/vpif_capture.h | 2 -- drivers/media/platform/davinci/vpif_display.c | 11 +---------- drivers/media/platform/davinci/vpif_display.h | 2 -- drivers/media/platform/rcar-vin/rcar-dma.c | 11 +---------- drivers/media/platform/rcar-vin/rcar-vin.h | 2 -- include/media/davinci/vpbe_display.h | 2 -- 13 files changed, 9 insertions(+), 88 deletions(-) (limited to 'include') diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index e749eb7c3be9..d22b09db9fd0 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1915,7 +1915,6 @@ static int vpfe_queue_setup(struct vb2_queue *vq, if (vq->num_buffers + *nbuffers < 3) *nbuffers = 3 - vq->num_buffers; - alloc_ctxs[0] = vpfe->alloc_ctx; if (*nplanes) { if (sizes[0] < size) @@ -2364,13 +2363,6 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) goto probe_out; /* Initialize videobuf2 queue as per the buffer type */ - vpfe->alloc_ctx = vb2_dma_contig_init_ctx(vpfe->pdev); - if (IS_ERR(vpfe->alloc_ctx)) { - vpfe_err(vpfe, "Failed to get the context\n"); - err = PTR_ERR(vpfe->alloc_ctx); - goto probe_out; - } - q = &vpfe->buffer_queue; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; @@ -2381,11 +2373,11 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->lock = &vpfe->lock; q->min_buffers_needed = 1; + q->dev = vpfe->pdev; err = vb2_queue_init(q); if (err) { vpfe_err(vpfe, "vb2_queue_init() failed\n"); - vb2_dma_contig_cleanup_ctx(vpfe->alloc_ctx); goto probe_out; } diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h index 777bf97fea57..17d7aa426788 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.h +++ b/drivers/media/platform/am437x/am437x-vpfe.h @@ -264,8 +264,6 @@ struct vpfe_device { struct v4l2_rect crop; /* Buffer queue used in video-buf */ 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; /* IRQ lock for DMA queue */ diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index d0092dae7a57..1e2442876d26 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -91,8 +91,6 @@ struct bcap_device { struct bcap_buffer *cur_frm; /* buffer queue used in videobuf2 */ 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 videobuf2 callback */ @@ -209,7 +207,6 @@ static int bcap_queue_setup(struct vb2_queue *vq, if (vq->num_buffers + *nbuffers < 2) *nbuffers = 2; - alloc_ctxs[0] = bcap_dev->alloc_ctx; if (*nplanes) return sizes[0] < bcap_dev->fmt.sizeimage ? -EINVAL : 0; @@ -820,12 +817,6 @@ static int bcap_probe(struct platform_device *pdev) } bcap_dev->ppi->priv = bcap_dev; - bcap_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); - if (IS_ERR(bcap_dev->alloc_ctx)) { - ret = PTR_ERR(bcap_dev->alloc_ctx); - goto err_free_ppi; - } - vfd = &bcap_dev->video_dev; /* initialize field of video device */ vfd->release = video_device_release_empty; @@ -839,7 +830,7 @@ static int bcap_probe(struct platform_device *pdev) if (ret) { v4l2_err(pdev->dev.driver, "Unable to register v4l2 device\n"); - goto err_cleanup_ctx; + goto err_free_ppi; } v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); @@ -863,6 +854,7 @@ static int bcap_probe(struct platform_device *pdev) q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->lock = &bcap_dev->mutex; q->min_buffers_needed = 1; + q->dev = &pdev->dev; ret = vb2_queue_init(q); if (ret) @@ -967,8 +959,6 @@ err_free_handler: v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); err_unreg_v4l2: v4l2_device_unregister(&bcap_dev->v4l2_dev); -err_cleanup_ctx: - vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); err_free_ppi: ppi_delete_instance(bcap_dev->ppi); err_free_dev: @@ -986,7 +976,6 @@ static int bcap_remove(struct platform_device *pdev) video_unregister_device(&bcap_dev->video_dev); v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); v4l2_device_unregister(v4l2_dev); - vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); ppi_delete_instance(bcap_dev->ppi); kfree(bcap_dev); return 0; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 133ab9f70f85..3d57c352cefa 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1151,9 +1151,6 @@ static int coda_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = size; - /* Set to vb2-dma-contig allocator context, ignored by vb2-vmalloc */ - alloc_ctxs[0] = ctx->dev->alloc_ctx; - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "get %d buffer(s) of size %d each.\n", *nbuffers, size); @@ -1599,6 +1596,7 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) * that videobuf2 will keep the value of bytesused intact. */ vq->allow_zero_bytesused = 1; + vq->dev = &ctx->dev->plat_dev->dev; return vb2_queue_init(vq); } @@ -2040,16 +2038,10 @@ static void coda_fw_callback(const struct firmware *fw, void *context) if (ret < 0) goto put_pm; - dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); - if (IS_ERR(dev->alloc_ctx)) { - v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n"); - goto put_pm; - } - dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); if (IS_ERR(dev->m2m_dev)) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); - goto rel_ctx; + goto put_pm; } for (i = 0; i < dev->devtype->num_vdevs; i++) { @@ -2072,8 +2064,6 @@ rel_vfd: while (--i >= 0) video_unregister_device(&dev->vfd[i]); v4l2_m2m_release(dev->m2m_dev); -rel_ctx: - vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); put_pm: pm_runtime_put_sync(&pdev->dev); } @@ -2324,8 +2314,6 @@ static int coda_remove(struct platform_device *pdev) if (dev->m2m_dev) v4l2_m2m_release(dev->m2m_dev); pm_runtime_disable(&pdev->dev); - if (dev->alloc_ctx) - vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); v4l2_device_unregister(&dev->v4l2_dev); destroy_workqueue(dev->workqueue); if (dev->iram.vaddr) diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 8f2c71e06966..53f96661683c 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -92,7 +92,6 @@ struct coda_dev { struct mutex coda_mutex; struct workqueue_struct *workqueue; struct v4l2_m2m_dev *m2m_dev; - struct vb2_alloc_ctx *alloc_ctx; struct list_head instances; unsigned long instance_mask; struct dentry *debugfs_root; diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 0abcdfe97a6c..2a4c2914d077 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -242,7 +242,6 @@ vpbe_buffer_queue_setup(struct vb2_queue *vq, /* Store number of buffers allocated in numbuffer member */ if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS) *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers; - alloc_ctxs[0] = layer->alloc_ctx; if (*nplanes) return sizes[0] < layer->pix_fmt.sizeimage ? -EINVAL : 0; @@ -1451,20 +1450,13 @@ static int vpbe_display_probe(struct platform_device *pdev) q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 1; q->lock = &disp_dev->dev[i]->opslock; + q->dev = disp_dev->vpbe_dev->pdev; err = vb2_queue_init(q); if (err) { v4l2_err(v4l2_dev, "vb2_queue_init() failed\n"); goto probe_out; } - disp_dev->dev[i]->alloc_ctx = - vb2_dma_contig_init_ctx(disp_dev->vpbe_dev->pdev); - if (IS_ERR(disp_dev->dev[i]->alloc_ctx)) { - v4l2_err(v4l2_dev, "Failed to get the context\n"); - err = PTR_ERR(disp_dev->dev[i]->alloc_ctx); - goto probe_out; - } - INIT_LIST_HEAD(&disp_dev->dev[i]->dma_queue); if (register_device(disp_dev->dev[i], disp_dev, pdev)) { @@ -1482,7 +1474,6 @@ probe_out: for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { /* Unregister video device */ if (disp_dev->dev[k] != NULL) { - vb2_dma_contig_cleanup_ctx(disp_dev->dev[k]->alloc_ctx); video_unregister_device(&disp_dev->dev[k]->video_dev); kfree(disp_dev->dev[k]); } @@ -1510,7 +1501,6 @@ static int vpbe_display_remove(struct platform_device *pdev) for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { /* Get the pointer to the layer object */ vpbe_display_layer = disp_dev->dev[i]; - vb2_dma_contig_cleanup_ctx(vpbe_display_layer->alloc_ctx); /* Unregister video device */ video_unregister_device(&vpbe_display_layer->video_dev); diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 08f7028c7560..d5afab0dd9e5 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -133,7 +133,6 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = size; - alloc_ctxs[0] = common->alloc_ctx; /* Calculate the offset for Y and C data in the buffer */ vpif_calculate_offsets(ch); @@ -1371,6 +1370,7 @@ static int vpif_probe_complete(void) q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 1; q->lock = &common->lock; + q->dev = vpif_dev; err = vb2_queue_init(q); if (err) { @@ -1378,13 +1378,6 @@ static int vpif_probe_complete(void) goto probe_out; } - common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev); - if (IS_ERR(common->alloc_ctx)) { - vpif_err("Failed to get the context\n"); - err = PTR_ERR(common->alloc_ctx); - goto probe_out; - } - INIT_LIST_HEAD(&common->dma_queue); /* Initialize the video_device structure */ @@ -1412,7 +1405,6 @@ probe_out: /* Get the pointer to the channel object */ ch = vpif_obj.dev[k]; common = &ch->common[k]; - vb2_dma_contig_cleanup_ctx(common->alloc_ctx); /* Unregister video device */ video_unregister_device(&ch->video_dev); } @@ -1546,7 +1538,6 @@ static int vpif_remove(struct platform_device *device) /* Get the pointer to the channel object */ ch = vpif_obj.dev[i]; common = &ch->common[VPIF_VIDEO_INDEX]; - vb2_dma_contig_cleanup_ctx(common->alloc_ctx); /* Unregister video device */ video_unregister_device(&ch->video_dev); kfree(vpif_obj.dev[i]); diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h index 4a7600929b61..9e35b6771d22 100644 --- a/drivers/media/platform/davinci/vpif_capture.h +++ b/drivers/media/platform/davinci/vpif_capture.h @@ -65,8 +65,6 @@ struct common_obj { struct v4l2_format fmt; /* Buffer queue used in video-buf */ 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 */ diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index f40755cf1bf2..5d77884b120a 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -126,7 +126,6 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = size; - alloc_ctxs[0] = common->alloc_ctx; /* Calculate the offset for Y and C data in the buffer */ vpif_calculate_offsets(ch); @@ -1191,19 +1190,13 @@ static int vpif_probe_complete(void) q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 1; q->lock = &common->lock; + q->dev = vpif_dev; err = vb2_queue_init(q); if (err) { vpif_err("vpif_display: vb2_queue_init() failed\n"); goto probe_out; } - common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev); - if (IS_ERR(common->alloc_ctx)) { - vpif_err("Failed to get the context\n"); - err = PTR_ERR(common->alloc_ctx); - goto probe_out; - } - INIT_LIST_HEAD(&common->dma_queue); /* register video device */ @@ -1233,7 +1226,6 @@ probe_out: for (k = 0; k < j; k++) { ch = vpif_obj.dev[k]; common = &ch->common[k]; - vb2_dma_contig_cleanup_ctx(common->alloc_ctx); video_unregister_device(&ch->video_dev); } return err; @@ -1355,7 +1347,6 @@ static int vpif_remove(struct platform_device *device) /* Get the pointer to the channel object */ ch = vpif_obj.dev[i]; common = &ch->common[VPIF_VIDEO_INDEX]; - vb2_dma_contig_cleanup_ctx(common->alloc_ctx); /* Unregister video device */ video_unregister_device(&ch->video_dev); kfree(vpif_obj.dev[i]); diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h index e7a1723a1b7a..af2765fdcea8 100644 --- a/drivers/media/platform/davinci/vpif_display.h +++ b/drivers/media/platform/davinci/vpif_display.h @@ -74,8 +74,6 @@ struct common_obj { struct v4l2_format fmt; /* Used to store the format */ 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 */ diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index dad3b031f778..4c5c529aafa7 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -979,7 +979,6 @@ static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, { struct rvin_dev *vin = vb2_get_drv_priv(vq); - alloc_ctxs[0] = vin->alloc_ctx; /* Make sure the image size is large enough. */ if (*nplanes) return sizes[0] < vin->format.sizeimage ? -EINVAL : 0; @@ -1129,9 +1128,6 @@ static struct vb2_ops rvin_qops = { void rvin_dma_remove(struct rvin_dev *vin) { - if (!IS_ERR_OR_NULL(vin->alloc_ctx)) - vb2_dma_contig_cleanup_ctx(vin->alloc_ctx); - mutex_destroy(&vin->lock); v4l2_device_unregister(&vin->v4l2_dev); @@ -1158,12 +1154,6 @@ int rvin_dma_probe(struct rvin_dev *vin, int irq) vin->queue_buf[i] = NULL; /* buffer queue */ - vin->alloc_ctx = vb2_dma_contig_init_ctx(vin->dev); - if (IS_ERR(vin->alloc_ctx)) { - ret = PTR_ERR(vin->alloc_ctx); - goto error; - } - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; q->lock = &vin->lock; @@ -1173,6 +1163,7 @@ int rvin_dma_probe(struct rvin_dev *vin, int irq) q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 2; + q->dev = vin->dev; ret = vb2_queue_init(q); if (ret < 0) { diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index a6dd6db246ab..31ad39a39937 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -94,7 +94,6 @@ struct rvin_graph_entity { * * @lock: protects @queue * @queue: vb2 buffers queue - * @alloc_ctx: allocation context for the vb2 @queue * * @qlock: protects @queue_buf, @buf_list, @continuous, @sequence * @state @@ -125,7 +124,6 @@ struct rvin_dev { struct mutex lock; struct vb2_queue queue; - struct vb2_alloc_ctx *alloc_ctx; spinlock_t qlock; struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM]; diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h index e14a9370b67e..12783fd823f8 100644 --- a/include/media/davinci/vpbe_display.h +++ b/include/media/davinci/vpbe_display.h @@ -81,8 +81,6 @@ struct vpbe_layer { * Buffer queue used in video-buf */ 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 */ -- cgit v1.2.3 From 36c0f8b32c4bd4f668cedfba6d97afaa84f055fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Apr 2016 09:15:05 -0300 Subject: [media] vb2: replace void *alloc_ctxs by struct device *alloc_devs Make this a proper typed array. Drop the old allocate context code since that is no longer used. Note that the memops functions now get a struct device pointer instead of the struct device ** that was there initially (actually a void pointer to a struct containing only a struct device pointer). This code is now a lot cleaner. Signed-off-by: Hans Verkuil Reviewed-by: Laurent Pinchart Cc: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/input/touchscreen/sur40.c | 2 +- drivers/media/dvb-frontends/rtl2832_sdr.c | 2 +- drivers/media/pci/cobalt/cobalt-v4l2.c | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 2 +- drivers/media/pci/cx23885/cx23885-dvb.c | 2 +- drivers/media/pci/cx23885/cx23885-vbi.c | 2 +- drivers/media/pci/cx23885/cx23885-video.c | 2 +- drivers/media/pci/cx25821/cx25821-video.c | 2 +- drivers/media/pci/cx88/cx88-blackbird.c | 2 +- drivers/media/pci/cx88/cx88-dvb.c | 2 +- drivers/media/pci/cx88/cx88-vbi.c | 2 +- drivers/media/pci/cx88/cx88-video.c | 2 +- drivers/media/pci/dt3155/dt3155.c | 2 +- drivers/media/pci/netup_unidvb/netup_unidvb_core.c | 2 +- drivers/media/pci/saa7134/saa7134-ts.c | 2 +- drivers/media/pci/saa7134/saa7134-vbi.c | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 2 +- drivers/media/pci/saa7134/saa7134.h | 2 +- drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c | 2 +- drivers/media/pci/solo6x10/solo6x10-v4l2.c | 2 +- drivers/media/pci/sta2x11/sta2x11_vip.c | 2 +- drivers/media/pci/tw68/tw68-video.c | 2 +- drivers/media/pci/tw686x/tw686x-video.c | 2 +- drivers/media/platform/am437x/am437x-vpfe.c | 4 +-- drivers/media/platform/blackfin/bfin_capture.c | 2 +- drivers/media/platform/coda/coda-common.c | 2 +- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 4 +-- drivers/media/platform/davinci/vpif_display.c | 4 +-- drivers/media/platform/exynos-gsc/gsc-core.h | 1 - drivers/media/platform/exynos-gsc/gsc-m2m.c | 2 +- drivers/media/platform/exynos4-is/fimc-capture.c | 2 +- drivers/media/platform/exynos4-is/fimc-isp-video.c | 2 +- drivers/media/platform/exynos4-is/fimc-lite.c | 2 +- drivers/media/platform/exynos4-is/fimc-m2m.c | 2 +- drivers/media/platform/m2m-deinterlace.c | 2 +- drivers/media/platform/marvell-ccic/mcam-core.c | 2 +- drivers/media/platform/mx2_emmaprp.c | 2 +- drivers/media/platform/omap3isp/ispvideo.c | 2 +- drivers/media/platform/rcar-vin/rcar-dma.c | 2 +- drivers/media/platform/rcar_jpu.c | 2 +- drivers/media/platform/s3c-camif/camif-capture.c | 2 +- drivers/media/platform/s5p-g2d/g2d.c | 2 +- drivers/media/platform/s5p-jpeg/jpeg-core.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 10 +++--- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 12 +++---- drivers/media/platform/s5p-tv/mixer_video.c | 2 +- drivers/media/platform/sh_veu.c | 2 +- drivers/media/platform/sh_vou.c | 2 +- drivers/media/platform/soc_camera/atmel-isi.c | 2 +- drivers/media/platform/soc_camera/rcar_vin.c | 2 +- .../platform/soc_camera/sh_mobile_ceu_camera.c | 2 +- drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 2 +- drivers/media/platform/ti-vpe/cal.c | 2 +- drivers/media/platform/ti-vpe/vpe.c | 2 +- drivers/media/platform/vim2m.c | 7 +--- drivers/media/platform/vivid/vivid-sdr-cap.c | 2 +- drivers/media/platform/vivid/vivid-vbi-cap.c | 2 +- drivers/media/platform/vivid/vivid-vbi-out.c | 2 +- drivers/media/platform/vivid/vivid-vid-cap.c | 7 +--- drivers/media/platform/vivid/vivid-vid-out.c | 7 +--- drivers/media/platform/vsp1/vsp1_video.c | 8 ++--- drivers/media/platform/xilinx/xilinx-dma.c | 2 +- drivers/media/usb/airspy/airspy.c | 2 +- drivers/media/usb/au0828/au0828-vbi.c | 2 +- drivers/media/usb/au0828/au0828-video.c | 2 +- drivers/media/usb/em28xx/em28xx-vbi.c | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 2 +- drivers/media/usb/go7007/go7007-v4l2.c | 2 +- drivers/media/usb/hackrf/hackrf.c | 2 +- drivers/media/usb/msi2500/msi2500.c | 2 +- drivers/media/usb/pwc/pwc-if.c | 2 +- drivers/media/usb/s2255/s2255drv.c | 2 +- drivers/media/usb/stk1160/stk1160-v4l.c | 2 +- drivers/media/usb/usbtv/usbtv-video.c | 2 +- drivers/media/usb/uvc/uvc_queue.c | 2 +- drivers/media/v4l2-core/videobuf2-core.c | 18 +++++----- drivers/media/v4l2-core/videobuf2-dma-contig.c | 39 +++----------------- drivers/media/v4l2-core/videobuf2-dma-sg.c | 42 ++++------------------ drivers/media/v4l2-core/videobuf2-vmalloc.c | 6 ++-- drivers/staging/media/davinci_vpfe/vpfe_video.c | 4 +-- drivers/staging/media/omap4iss/iss_video.c | 2 +- drivers/staging/media/tw686x-kh/tw686x-kh-video.c | 2 +- drivers/usb/gadget/function/uvc_queue.c | 2 +- include/media/videobuf2-core.h | 18 +++++----- include/media/videobuf2-dma-contig.h | 2 -- include/media/videobuf2-dma-sg.h | 3 -- samples/v4l/v4l2-pci-skeleton.c | 2 +- 88 files changed, 128 insertions(+), 208 deletions(-) (limited to 'include') diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index cc4bd3e53b58..f124f3af0de1 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -645,7 +645,7 @@ static void sur40_disconnect(struct usb_interface *interface) */ static int sur40_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { if (q->num_buffers + *nbuffers < 3) *nbuffers = 3 - q->num_buffers; diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 47a480a7d46c..6e22af36b637 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -452,7 +452,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, /* Videobuf2 operations */ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) + unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); struct platform_device *pdev = dev->pdev; diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index 6c19cdfcf3b1..d05672fe9ff9 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -45,7 +45,7 @@ static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60; static int cobalt_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cobalt_stream *s = q->drv_priv; unsigned size = s->stride * s->height; diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 0174d08d0c27..efec2d1a7afd 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1140,7 +1140,7 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx23885_dev *dev = q->drv_priv; diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 6ad07f5b5749..95aaa2e2afeb 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -94,7 +94,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx23885_tsport *port = q->drv_priv; diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 2de9485013e1..75e7fa7b1121 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -122,7 +122,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx23885_dev *dev = q->drv_priv; unsigned lines = VBI_PAL_LINE_COUNT; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 3ff86d6dbc60..6d735222a958 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -335,7 +335,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx23885_dev *dev = q->drv_priv; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 45fc23e11b0c..adcd09be347d 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -143,7 +143,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) static int cx25821_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx25821_channel *chan = q->drv_priv; unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3; diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 7c026c1ca1fe..04fe9af2a802 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -639,7 +639,7 @@ static int blackbird_stop_codec(struct cx8802_dev *dev) static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx8802_dev *dev = q->drv_priv; diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 4d91d1697419..5bb63e7a5691 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -84,7 +84,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx8802_dev *dev = q->drv_priv; diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index 2479f7deccbf..d3237cf8ffa3 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -109,7 +109,7 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx8800_dev *dev = q->drv_priv; diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 9764d6fb382e..5dc1e3f08d50 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -431,7 +431,7 @@ static int restart_video_queue(struct cx8800_dev *dev, static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cx8800_dev *dev = q->drv_priv; struct cx88_core *core = dev->core; diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index ec8f58a710c7..6a219694b225 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -133,7 +133,7 @@ static int wait_i2c_reg(void __iomem *addr) static int dt3155_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct dt3155_priv *pd = vb2_get_drv_priv(vq); diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index d278d4e151a0..5e3f41b7b3fe 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -293,7 +293,7 @@ static int netup_unidvb_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) + struct device *alloc_devs[]) { struct netup_dma *dma = vb2_get_drv_priv(vq); diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c index 8c68a934e22b..7eaf36a41db9 100644 --- a/drivers/media/pci/saa7134/saa7134-ts.c +++ b/drivers/media/pci/saa7134/saa7134-ts.c @@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare); int saa7134_ts_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct saa7134_dmaqueue *dmaq = q->drv_priv; struct saa7134_dev *dev = dmaq->dev; diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index e9bffb3569ba..cf9a31e0a390 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -140,7 +140,7 @@ static int buffer_prepare(struct vb2_buffer *vb2) static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct saa7134_dmaqueue *dmaq = q->drv_priv; struct saa7134_dev *dev = dmaq->dev; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 965ade72f5c5..8a6ebd087889 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -963,7 +963,7 @@ static int buffer_prepare(struct vb2_buffer *vb2) static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct saa7134_dmaqueue *dmaq = q->drv_priv; struct saa7134_dev *dev = dmaq->dev; diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 41c01588af37..3849083526a7 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -853,7 +853,7 @@ int saa7134_ts_buffer_init(struct vb2_buffer *vb2); int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2); int saa7134_ts_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]); + unsigned int sizes[], struct device *alloc_devs[]); int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count); void saa7134_ts_stop_streaming(struct vb2_queue *vq); diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index f48ef3392576..8b1cde57c817 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -664,7 +664,7 @@ static int solo_ring_thread(void *data) static int solo_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], - void *alloc_ctxs[]) + struct device *alloc_devs[]) { sizes[0] = FRAME_BUF_SIZE; *num_planes = 1; diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index 11cf03be106f..b4be47969b6b 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -315,7 +315,7 @@ static void solo_stop_thread(struct solo_dev *solo_dev) static int solo_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct solo_dev *solo_dev = vb2_get_drv_priv(q); diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 2844df23ada2..aeb2b4e2db35 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -265,7 +265,7 @@ static void vip_active_buf_next(struct sta2x11_vip *vip) /* Videobuf2 Operations */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct sta2x11_vip *vip = vb2_get_drv_priv(vq); diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index c675f9abbb24..5e8212845c87 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -378,7 +378,7 @@ static int tw68_buffer_count(unsigned int size, unsigned int count) static int tw68_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct tw68_dev *dev = vb2_get_drv_priv(q); unsigned tot_bufs = q->num_buffers + *num_buffers; diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index d380a8d8e462..973fa951644b 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -401,7 +401,7 @@ static const struct tw686x_format *format_by_fourcc(unsigned int fourcc) static int tw686x_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); unsigned int szimage = diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index d22b09db9fd0..b33b9e35e60e 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1901,14 +1901,14 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe) * @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 + * @alloc_devs: ptr to allocation context * * This callback function is called when reqbuf() is called to adjust * the buffer count and buffer size */ static int vpfe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct vpfe_device *vpfe = vb2_get_drv_priv(vq); unsigned size = vpfe->fmt.fmt.pix.sizeimage; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 1e2442876d26..8eb03397d736 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -201,7 +201,7 @@ static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) static int bcap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3d57c352cefa..3e9b7c817684 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1139,7 +1139,7 @@ static void set_default_params(struct coda_ctx *ctx) */ static int coda_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct coda_ctx *ctx = vb2_get_drv_priv(vq); struct coda_q_data *q_data; diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 2a4c2914d077..0b1709e96673 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -230,7 +230,7 @@ static int vpbe_buffer_prepare(struct vb2_buffer *vb) static int vpbe_buffer_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { /* Get the file handle object and layer object */ diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index d5afab0dd9e5..5104cc0ee40e 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -107,14 +107,14 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) * @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 + * @alloc_devs: 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_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct channel_obj *ch = vb2_get_drv_priv(vq); struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 5d77884b120a..75b27233ec2f 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -102,14 +102,14 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) * @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 + * @alloc_devs: 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_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct channel_obj *ch = vb2_get_drv_priv(vq); struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index 5c48329381fa..7ad7b9dc2243 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -327,7 +327,6 @@ struct gsc_driverdata { * @irq_queue: interrupt handler waitqueue * @m2m: memory-to-memory V4L2 device information * @state: flags used to synchronize m2m and capture mode operation - * @alloc_ctx: videobuf2 memory allocator context * @vdev: video device for G-Scaler instance */ struct gsc_dev { diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 622709c45413..ec6494cbdd45 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -213,7 +213,7 @@ put_device: static int gsc_m2m_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct gsc_ctx *ctx = vb2_get_drv_priv(vq); struct gsc_frame *frame; diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 512b254914bc..fdec499fbbda 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -340,7 +340,7 @@ int fimc_capture_resume(struct fimc_dev *fimc) static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct fimc_ctx *ctx = vq->drv_priv; struct fimc_frame *frame = &ctx->d_frame; diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index abc338962d80..400ce0cb0c0d 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -40,7 +40,7 @@ static int isp_video_capture_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct fimc_isp *isp = vb2_get_drv_priv(vq); struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index f5a27a90e9d1..a0f149fb88e1 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -357,7 +357,7 @@ static void stop_streaming(struct vb2_queue *q) static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct fimc_lite *fimc = vq->drv_priv; struct flite_frame *frame = &fimc->out_frame; diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index f4f76225ffed..b1309e114edb 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -174,7 +174,7 @@ static void fimc_job_abort(void *priv) static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct fimc_ctx *ctx = vb2_get_drv_priv(vq); struct fimc_frame *f; diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 15110ea89c56..0fcb5c78031d 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -798,7 +798,7 @@ struct vb2_dc_conf { static int deinterlace_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); struct deinterlace_q_data *q_data; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 8a1f12d08c0c..9171174521b2 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1051,7 +1051,7 @@ static int mcam_read_setup(struct mcam_camera *cam) static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, unsigned int *num_planes, unsigned int sizes[], - void *alloc_ctxs[]) + struct device *alloc_devs[]) { struct mcam_camera *cam = vb2_get_drv_priv(vq); int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2; diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 88b3d982a2da..c639406fe72e 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -689,7 +689,7 @@ static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { */ static int emmaprp_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq); struct emmaprp_q_data *q_data; diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 486b8754110f..7d9f35976d18 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -331,7 +331,7 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) static int isp_video_queue_setup(struct vb2_queue *queue, unsigned int *count, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct isp_video_fh *vfh = vb2_get_drv_priv(queue); struct isp_video *video = vfh->video; diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 4c5c529aafa7..496aa97b6400 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -974,7 +974,7 @@ static void return_all_buffers(struct rvin_dev *vin, static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) + struct device *alloc_devs[]) { struct rvin_dev *vin = vb2_get_drv_priv(vq); diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index d81c41035bb6..16782ceb29c3 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -1014,7 +1014,7 @@ error_free: */ static int jpu_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct jpu_ctx *ctx = vb2_get_drv_priv(vq); struct jpu_q_data *q_data; diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 5eb5df1c6f75..0413a861a59a 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -437,7 +437,7 @@ static void stop_streaming(struct vb2_queue *vq) static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct camif_vp *vp = vb2_get_drv_priv(vq); struct camif_frame *frame = &vp->out_frame; diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 2aeb950ba91f..391dd7a7b362 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -103,7 +103,7 @@ static struct g2d_frame *get_frame(struct g2d_ctx *ctx, static int g2d_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct g2d_ctx *ctx = vb2_get_drv_priv(vq); struct g2d_frame *f = get_frame(ctx, vq->type); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index d8842c482f0c..785e6936c881 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2436,7 +2436,7 @@ static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = { static int s5p_jpeg_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_jpeg_q_data *q_data = NULL; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index ae98a5568b69..47c997d9e8cb 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -890,7 +890,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, unsigned int *plane_count, unsigned int psize[], - void *allocators[]) + struct device *alloc_devs[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); struct s5p_mfc_dev *dev = ctx->dev; @@ -931,14 +931,14 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, psize[1] = ctx->chroma_size; if (IS_MFCV6_PLUS(dev)) - allocators[0] = &ctx->dev->mem_dev_l; + alloc_devs[0] = ctx->dev->mem_dev_l; else - allocators[0] = &ctx->dev->mem_dev_r; - allocators[1] = &ctx->dev->mem_dev_l; + alloc_devs[0] = ctx->dev->mem_dev_r; + alloc_devs[1] = ctx->dev->mem_dev_l; } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && ctx->state == MFCINST_INIT) { psize[0] = ctx->dec_src_buf_size; - allocators[0] = &ctx->dev->mem_dev_l; + alloc_devs[0] = ctx->dev->mem_dev_l; } else { mfc_err("This video node is dedicated to decoding. Decoding not initialized\n"); return -EINVAL; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index b95796a0cc33..fcc2e054c61f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1812,7 +1812,7 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, unsigned int *plane_count, - unsigned int psize[], void *allocators[]) + unsigned int psize[], struct device *alloc_devs[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); struct s5p_mfc_dev *dev = ctx->dev; @@ -1832,7 +1832,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, if (*buf_count > MFC_MAX_BUFFERS) *buf_count = MFC_MAX_BUFFERS; psize[0] = ctx->enc_dst_buf_size; - allocators[0] = &ctx->dev->mem_dev_l; + alloc_devs[0] = ctx->dev->mem_dev_l; } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (ctx->src_fmt) *plane_count = ctx->src_fmt->num_planes; @@ -1848,11 +1848,11 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, psize[1] = ctx->chroma_size; if (IS_MFCV6_PLUS(dev)) { - allocators[0] = &ctx->dev->mem_dev_l; - allocators[1] = &ctx->dev->mem_dev_l; + alloc_devs[0] = ctx->dev->mem_dev_l; + alloc_devs[1] = ctx->dev->mem_dev_l; } else { - allocators[0] = &ctx->dev->mem_dev_r; - allocators[1] = &ctx->dev->mem_dev_r; + alloc_devs[0] = ctx->dev->mem_dev_r; + alloc_devs[1] = ctx->dev->mem_dev_r; } } else { mfc_err("invalid queue type: %d\n", vq->type); diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 6c4d1b91f325..ee74e2b44d69 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -874,7 +874,7 @@ static const struct v4l2_file_operations mxr_fops = { static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) + struct device *alloc_devs[]) { struct mxr_layer *layer = vb2_get_drv_priv(vq); const struct mxr_format *fmt = layer->fmt; diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index afd21c9f1a02..15a562af13c7 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -865,7 +865,7 @@ static const struct v4l2_ioctl_ops sh_veu_ioctl_ops = { static int sh_veu_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct sh_veu_dev *veu = vb2_get_drv_priv(vq); struct sh_veu_vfmt *vfmt = sh_veu_get_vfmt(veu, vq->type); diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 59830a491592..e1f39b4cf1cd 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -244,7 +244,7 @@ static void sh_vou_stream_config(struct sh_vou_device *vou_dev) /* Locking: caller holds fop_lock mutex */ static int sh_vou_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); struct v4l2_pix_format *pix = &vou_dev->pix; diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 899b93ad1e4f..30211f6b4483 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -303,7 +303,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) ------------------------------------------------------------------*/ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index dadc5b3e1bb2..9c137522c660 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -533,7 +533,7 @@ struct rcar_vin_cam { static int rcar_vin_videobuf_setup(struct vb2_queue *vq, unsigned int *count, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 8f87fbec6f51..02b519dde42a 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -210,7 +210,7 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) */ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, unsigned int *count, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index b3e8b5afeb61..3b1ac687d0df 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -439,7 +439,7 @@ static void bdisp_ctrls_delete(struct bdisp_ctx *ctx) static int bdisp_queue_setup(struct vb2_queue *vq, unsigned int *nb_buf, unsigned int *nb_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct bdisp_ctx *ctx = vb2_get_drv_priv(vq); struct bdisp_frame *frame = ctx_get_frame(ctx, vq->type); diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 51ebf32c659c..e967fcfdc1d8 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1225,7 +1225,7 @@ static int cal_enum_frameintervals(struct file *file, void *priv, */ static int cal_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct cal_ctx *ctx = vb2_get_drv_priv(vq); unsigned size = ctx->v_fmt.fmt.pix.sizeimage; diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 3fefd8ad37af..55a1458ac783 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1796,7 +1796,7 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = { */ static int vpe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { int i; struct vpe_ctx *ctx = vb2_get_drv_priv(vq); diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index c4b5fab83666..6b17015048ae 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -711,7 +711,7 @@ static const struct v4l2_ioctl_ops vim2m_ioctl_ops = { static int vim2m_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct vim2m_ctx *ctx = vb2_get_drv_priv(vq); struct vim2m_q_data *q_data; @@ -731,11 +731,6 @@ static int vim2m_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = size; - /* - * videobuf2-vmalloc allocator is context-less so no need to set - * alloc_ctxs array. - */ - dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); return 0; diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 1428e31a2875..ebd7b9c4dd83 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -213,7 +213,7 @@ static int vivid_thread_sdr_cap(void *data) static int sdr_cap_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], void *alloc_ctxs[]) + unsigned sizes[], struct device *alloc_devs[]) { /* 2 = max 16-bit sample returned */ sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2; diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c index cda45a582bfe..d66ef95dd2b5 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -137,7 +137,7 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, static int vbi_cap_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], void *alloc_ctxs[]) + unsigned sizes[], struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); bool is_60hz = dev->std_cap & V4L2_STD_525_60; diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c index 3c5a469e6f49..d2989195cf03 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.c +++ b/drivers/media/platform/vivid/vivid-vbi-out.c @@ -29,7 +29,7 @@ static int vbi_out_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], void *alloc_ctxs[]) + unsigned sizes[], struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); bool is_60hz = dev->std_out & V4L2_STD_525_60; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index fdca33fc20b0..52ea6d74b70b 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -97,7 +97,7 @@ static const struct v4l2_discrete_probe webcam_probe = { static int vid_cap_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], void *alloc_ctxs[]) + unsigned sizes[], struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); unsigned buffers = tpg_g_buffers(&dev->tpg); @@ -144,11 +144,6 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, *nplanes = buffers; - /* - * videobuf2-vmalloc allocator is context-less so no need to set - * alloc_ctxs array. - */ - dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); for (p = 0; p < buffers; p++) dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index f92f4496d527..dd609eea4753 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -34,7 +34,7 @@ static int vid_out_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], void *alloc_ctxs[]) + unsigned sizes[], struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); const struct vivid_fmt *vfmt = dev->fmt_out; @@ -87,11 +87,6 @@ static int vid_out_queue_setup(struct vb2_queue *vq, *nplanes = planes; - /* - * videobuf2-vmalloc allocator is context-less so no need to set - * alloc_ctxs array. - */ - dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); for (p = 0; p < planes; p++) dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 0e94e3b6fcf1..424a54122190 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -519,8 +519,8 @@ static void vsp1_video_pipeline_put(struct vsp1_pipeline *pipe) static int vsp1_video_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) { struct vsp1_video *video = vb2_get_drv_priv(vq); const struct v4l2_pix_format_mplane *format = &video->rwpf->format; @@ -530,10 +530,9 @@ vsp1_video_queue_setup(struct vb2_queue *vq, if (*nplanes != format->num_planes) return -EINVAL; - for (i = 0; i < *nplanes; i++) { + for (i = 0; i < *nplanes; i++) if (sizes[i] < format->plane_fmt[i].sizeimage) return -EINVAL; - } return 0; } @@ -979,7 +978,6 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1, video_set_drvdata(&video->video, video); - /* ... and the buffers queue... */ video->queue.type = video->type; video->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; video->queue.lock = &video->lock; diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 3838e11fc15f..7ae1a134b1ff 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -318,7 +318,7 @@ static void xvip_dma_complete(void *param) static int xvip_dma_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct xvip_dma *dma = vb2_get_drv_priv(vq); diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 87c12930416f..d807d5875f7e 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -488,7 +488,7 @@ static void airspy_disconnect(struct usb_interface *intf) /* Videobuf2 operations */ static int airspy_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) + unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct airspy *s = vb2_get_drv_priv(vq); diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index b4efc103ae57..e0930ce59b8d 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -32,7 +32,7 @@ static int vbi_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct au0828_dev *dev = vb2_get_drv_priv(vq); unsigned long size = dev->vbi_width * dev->vbi_height * 2; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 7d0ec4cb248c..82b026985868 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -698,7 +698,7 @@ int au0828_v4l2_device_register(struct usb_interface *interface, static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct au0828_dev *dev = vb2_get_drv_priv(vq); unsigned long size = dev->height * dev->bytesperline; diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index fe94c9225dd7..836c6b53b16c 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -33,7 +33,7 @@ static int vbi_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct em28xx *dev = vb2_get_drv_priv(vq); struct em28xx_v4l2 *v4l2 = dev->v4l2; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 44834b2eff55..7968695217f3 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1013,7 +1013,7 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct em28xx *dev = vb2_get_drv_priv(vq); struct em28xx_v4l2 *v4l2 = dev->v4l2; diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index ea01ee5df60a..af8458996d91 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -370,7 +370,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int go7007_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { sizes[0] = GO7007_BUF_SIZE; *num_planes = 1; diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 9e700caf0d66..b1e229a44192 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -760,7 +760,7 @@ static void hackrf_return_all_buffers(struct vb2_queue *vq, static int hackrf_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) + unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct hackrf_dev *dev = vb2_get_drv_priv(vq); diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 2d33033682af..e7f167d44c61 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -618,7 +618,7 @@ static int msi2500_querycap(struct file *file, void *fh, static int msi2500_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) + struct device *alloc_devs[]) { struct msi2500_dev *dev = vb2_get_drv_priv(vq); diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 18aed5dd325e..dd43652fdef8 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -573,7 +573,7 @@ static void pwc_video_release(struct v4l2_device *v) static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct pwc_device *pdev = vb2_get_drv_priv(vq); int size; diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 9acdaa3716fb..43ba71a7d02b 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -662,7 +662,7 @@ static void s2255_fillbuff(struct s2255_vc *vc, static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct s2255_vc *vc = vb2_get_drv_priv(vq); if (*nbuffers < S2255_MIN_BUFS) diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 7ddbc0274f12..5fab3bee8c74 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -666,7 +666,7 @@ static const struct v4l2_ioctl_ops stk1160_ioctl_ops = { */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct stk1160 *dev = vb2_get_drv_priv(vq); unsigned long size; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index f6cfad46547e..7e282048f932 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -608,7 +608,7 @@ static struct v4l2_file_operations usbtv_fops = { static int usbtv_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) + unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct usbtv *usbtv = vb2_get_drv_priv(vq); unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32); diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 54394722756f..773fefb52d7a 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -71,7 +71,7 @@ static void uvc_queue_return_buffers(struct uvc_video_queue *queue, static int uvc_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_streaming *stream = uvc_queue_to_stream(queue); diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index aabb03e406f0..0b9e71e48ddb 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -207,7 +207,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) unsigned long size = PAGE_ALIGN(vb->planes[plane].length); mem_priv = call_ptr_memop(vb, alloc, - q->alloc_ctx[plane] ? : &q->dev, + q->alloc_devs[plane] ? : q->dev, q->dma_attrs, size, dma_dir, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; @@ -738,7 +738,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, */ num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME); num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed); - memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); q->memory = memory; /* @@ -746,7 +746,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * Driver also sets the size and allocator context for each plane. */ ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, - plane_sizes, q->alloc_ctx); + plane_sizes, q->alloc_devs); if (ret) return ret; @@ -779,7 +779,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, num_planes = 0; ret = call_qop(q, queue_setup, q, &num_buffers, - &num_planes, plane_sizes, q->alloc_ctx); + &num_planes, plane_sizes, q->alloc_devs); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -845,7 +845,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, } if (!q->num_buffers) { - memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); q->memory = memory; q->waiting_for_buffers = !q->is_output; } @@ -862,7 +862,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * buffer and their sizes are acceptable */ ret = call_qop(q, queue_setup, q, &num_buffers, - &num_planes, plane_sizes, q->alloc_ctx); + &num_planes, plane_sizes, q->alloc_devs); if (ret) return ret; @@ -885,7 +885,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * queue driver has set up */ ret = call_qop(q, queue_setup, q, &num_buffers, - &num_planes, plane_sizes, q->alloc_ctx); + &num_planes, plane_sizes, q->alloc_devs); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -1133,7 +1133,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) /* Acquire each plane's memory */ mem_priv = call_ptr_memop(vb, get_userptr, - q->alloc_ctx[plane] ? : &q->dev, + q->alloc_devs[plane] ? : q->dev, planes[plane].m.userptr, planes[plane].length, dma_dir); if (IS_ERR_OR_NULL(mem_priv)) { @@ -1258,7 +1258,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) /* Acquire each plane's memory */ mem_priv = call_ptr_memop(vb, attach_dmabuf, - q->alloc_ctx[plane] ? : &q->dev, + q->alloc_devs[plane] ? : q->dev, dbuf, planes[plane].length, dma_dir); if (IS_ERR(mem_priv)) { dprintk(1, "failed to attach dmabuf\n"); diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index a7825c62ad88..863f658a3fa1 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -21,10 +21,6 @@ #include #include -struct vb2_dc_conf { - struct device *dev; -}; - struct vb2_dc_buf { struct device *dev; void *vaddr; @@ -139,12 +135,10 @@ static void vb2_dc_put(void *buf_priv) kfree(buf); } -static void *vb2_dc_alloc(void *alloc_ctx, const struct dma_attrs *attrs, +static void *vb2_dc_alloc(struct device *dev, const struct dma_attrs *attrs, unsigned long size, enum dma_data_direction dma_dir, gfp_t gfp_flags) { - struct vb2_dc_conf *conf = alloc_ctx; - struct device *dev = conf->dev; struct vb2_dc_buf *buf; buf = kzalloc(sizeof *buf, GFP_KERNEL); @@ -479,10 +473,9 @@ static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn } #endif -static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, +static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, unsigned long size, enum dma_data_direction dma_dir) { - struct vb2_dc_conf *conf = alloc_ctx; struct vb2_dc_buf *buf; struct frame_vector *vec; unsigned long offset; @@ -510,7 +503,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, if (!buf) return ERR_PTR(-ENOMEM); - buf->dev = conf->dev; + buf->dev = dev; buf->dma_dir = dma_dir; offset = vaddr & ~PAGE_MASK; @@ -677,10 +670,9 @@ static void vb2_dc_detach_dmabuf(void *mem_priv) kfree(buf); } -static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, +static void *vb2_dc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, unsigned long size, enum dma_data_direction dma_dir) { - struct vb2_dc_conf *conf = alloc_ctx; struct vb2_dc_buf *buf; struct dma_buf_attachment *dba; @@ -691,7 +683,7 @@ static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, if (!buf) return ERR_PTR(-ENOMEM); - buf->dev = conf->dev; + buf->dev = dev; /* create attachment for the dmabuf with the user device */ dba = dma_buf_attach(dbuf, buf->dev); if (IS_ERR(dba)) { @@ -730,27 +722,6 @@ const struct vb2_mem_ops vb2_dma_contig_memops = { }; EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); -void *vb2_dma_contig_init_ctx(struct device *dev) -{ - struct vb2_dc_conf *conf; - - conf = kzalloc(sizeof *conf, GFP_KERNEL); - if (!conf) - return ERR_PTR(-ENOMEM); - - conf->dev = dev; - - return conf; -} -EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx); - -void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) -{ - if (!IS_ERR_OR_NULL(alloc_ctx)) - kfree(alloc_ctx); -} -EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); - /** * vb2_dma_contig_set_max_seg_size() - configure DMA max segment size * @dev: device for configuring DMA parameters diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index e7153f708ade..a39db8a6db7a 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -30,10 +30,6 @@ module_param(debug, int, 0644); printk(KERN_DEBUG "vb2-dma-sg: " fmt, ## arg); \ } while (0) -struct vb2_dma_sg_conf { - struct device *dev; -}; - struct vb2_dma_sg_buf { struct device *dev; void *vaddr; @@ -99,11 +95,10 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf, return 0; } -static void *vb2_dma_sg_alloc(void *alloc_ctx, const struct dma_attrs *dma_attrs, +static void *vb2_dma_sg_alloc(struct device *dev, const struct dma_attrs *dma_attrs, unsigned long size, enum dma_data_direction dma_dir, gfp_t gfp_flags) { - struct vb2_dma_sg_conf *conf = alloc_ctx; struct vb2_dma_sg_buf *buf; struct sg_table *sgt; int ret; @@ -112,7 +107,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, const struct dma_attrs *dma_attrs dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); - if (WARN_ON(alloc_ctx == NULL)) + if (WARN_ON(dev == NULL)) return NULL; buf = kzalloc(sizeof *buf, GFP_KERNEL); if (!buf) @@ -141,7 +136,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, const struct dma_attrs *dma_attrs goto fail_table_alloc; /* Prevent the device from being released while the buffer is used */ - buf->dev = get_device(conf->dev); + buf->dev = get_device(dev); sgt = &buf->sg_table; /* @@ -227,11 +222,10 @@ static void vb2_dma_sg_finish(void *buf_priv) dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); } -static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, +static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr, unsigned long size, enum dma_data_direction dma_dir) { - struct vb2_dma_sg_conf *conf = alloc_ctx; struct vb2_dma_sg_buf *buf; struct sg_table *sgt; DEFINE_DMA_ATTRS(attrs); @@ -243,7 +237,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, return NULL; buf->vaddr = NULL; - buf->dev = conf->dev; + buf->dev = dev; buf->dma_dir = dma_dir; buf->offset = vaddr & ~PAGE_MASK; buf->size = size; @@ -617,10 +611,9 @@ static void vb2_dma_sg_detach_dmabuf(void *mem_priv) kfree(buf); } -static void *vb2_dma_sg_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, +static void *vb2_dma_sg_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, unsigned long size, enum dma_data_direction dma_dir) { - struct vb2_dma_sg_conf *conf = alloc_ctx; struct vb2_dma_sg_buf *buf; struct dma_buf_attachment *dba; @@ -631,7 +624,7 @@ static void *vb2_dma_sg_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, if (!buf) return ERR_PTR(-ENOMEM); - buf->dev = conf->dev; + buf->dev = dev; /* create attachment for the dmabuf with the user device */ dba = dma_buf_attach(dbuf, buf->dev); if (IS_ERR(dba)) { @@ -673,27 +666,6 @@ const struct vb2_mem_ops vb2_dma_sg_memops = { }; EXPORT_SYMBOL_GPL(vb2_dma_sg_memops); -void *vb2_dma_sg_init_ctx(struct device *dev) -{ - struct vb2_dma_sg_conf *conf; - - conf = kzalloc(sizeof(*conf), GFP_KERNEL); - if (!conf) - return ERR_PTR(-ENOMEM); - - conf->dev = dev; - - return conf; -} -EXPORT_SYMBOL_GPL(vb2_dma_sg_init_ctx); - -void vb2_dma_sg_cleanup_ctx(void *alloc_ctx) -{ - if (!IS_ERR_OR_NULL(alloc_ctx)) - kfree(alloc_ctx); -} -EXPORT_SYMBOL_GPL(vb2_dma_sg_cleanup_ctx); - MODULE_DESCRIPTION("dma scatter/gather memory handling routines for videobuf2"); MODULE_AUTHOR("Andrzej Pietrasiewicz"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index fb94c80e9aa8..7e8a07ed8d82 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -33,7 +33,7 @@ struct vb2_vmalloc_buf { static void vb2_vmalloc_put(void *buf_priv); -static void *vb2_vmalloc_alloc(void *alloc_ctx, const struct dma_attrs *attrs, +static void *vb2_vmalloc_alloc(struct device *dev, const struct dma_attrs *attrs, unsigned long size, enum dma_data_direction dma_dir, gfp_t gfp_flags) { @@ -70,7 +70,7 @@ static void vb2_vmalloc_put(void *buf_priv) } } -static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, +static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, unsigned long size, enum dma_data_direction dma_dir) { @@ -404,7 +404,7 @@ static void vb2_vmalloc_detach_dmabuf(void *mem_priv) kfree(buf); } -static void *vb2_vmalloc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, +static void *vb2_vmalloc_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, unsigned long size, enum dma_data_direction dma_dir) { struct vb2_vmalloc_buf *buf; diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 77e66e75ffce..3319fb8f7d01 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -1091,7 +1091,7 @@ vpfe_g_dv_timings(struct file *file, void *fh, * @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 + * @alloc_devs: ptr to allocation context * * This callback function is called when reqbuf() is called to adjust * the buffer nbuffers and buffer size @@ -1099,7 +1099,7 @@ vpfe_g_dv_timings(struct file *file, void *fh, static int vpfe_buffer_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct vpfe_fh *fh = vb2_get_drv_priv(vq); struct vpfe_video_device *video = fh->video; diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 3c077e378267..90b7ff56722d 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -298,7 +298,7 @@ iss_video_check_format(struct iss_video *video, struct iss_video_fh *vfh) static int iss_video_queue_setup(struct vb2_queue *vq, unsigned int *count, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct iss_video_fh *vfh = vb2_get_drv_priv(vq); struct iss_video *video = vfh->video; diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-video.c b/drivers/staging/media/tw686x-kh/tw686x-kh-video.c index 4e2ef9decbe2..9bf32aec2fc6 100644 --- a/drivers/staging/media/tw686x-kh/tw686x-kh-video.c +++ b/drivers/staging/media/tw686x-kh/tw686x-kh-video.c @@ -130,7 +130,7 @@ static void tw686x_get_format(struct tw686x_video_channel *vc, static int tw686x_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], - void *alloc_ctxs[]) + struct device *alloc_devs[]) { struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); unsigned int size = vc->width * vc->height * vc->format->depth / 8; diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 912694f3d54e..6377e9fee6e5 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -43,7 +43,7 @@ static int uvc_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_video *video = container_of(queue, struct uvc_video, queue); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index d38668c2ea06..bea81c9e3758 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -56,7 +56,7 @@ struct vb2_threadio_data; * @put_userptr: inform the allocator that a USERPTR buffer will no longer * be used. * @attach_dmabuf: attach a shared struct dma_buf for a hardware operation; - * used for DMABUF memory types; alloc_ctx is the alloc context + * used for DMABUF memory types; dev is the alloc device * dbuf is the shared dma_buf; returns NULL on failure; * allocator private per-buffer structure on success; * this needs to be used for further accesses to the buffer. @@ -92,13 +92,13 @@ struct vb2_threadio_data; * unmap_dmabuf. */ struct vb2_mem_ops { - void *(*alloc)(void *alloc_ctx, const struct dma_attrs *attrs, + void *(*alloc)(struct device *dev, const struct dma_attrs *attrs, unsigned long size, enum dma_data_direction dma_dir, gfp_t gfp_flags); void (*put)(void *buf_priv); struct dma_buf *(*get_dmabuf)(void *buf_priv, unsigned long flags); - void *(*get_userptr)(void *alloc_ctx, unsigned long vaddr, + void *(*get_userptr)(struct device *dev, unsigned long vaddr, unsigned long size, enum dma_data_direction dma_dir); void (*put_userptr)(void *buf_priv); @@ -106,7 +106,7 @@ struct vb2_mem_ops { void (*prepare)(void *buf_priv); void (*finish)(void *buf_priv); - void *(*attach_dmabuf)(void *alloc_ctx, struct dma_buf *dbuf, + void *(*attach_dmabuf)(struct device *dev, struct dma_buf *dbuf, unsigned long size, enum dma_data_direction dma_dir); void (*detach_dmabuf)(void *buf_priv); @@ -281,7 +281,7 @@ struct vb2_buffer { * in *num_buffers, the required number of planes per * buffer in *num_planes, the size of each plane should be * set in the sizes[] array and optional per-plane - * allocator specific context in the alloc_ctxs[] array. + * allocator specific device in the alloc_devs[] array. * When called from VIDIOC_REQBUFS, *num_planes == 0, the * driver has to use the currently configured format to * determine the plane sizes and *num_buffers is the total @@ -355,7 +355,7 @@ struct vb2_buffer { struct vb2_ops { int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]); + unsigned int sizes[], struct device *alloc_devs[]); void (*wait_prepare)(struct vb2_queue *q); void (*wait_finish)(struct vb2_queue *q); @@ -401,7 +401,7 @@ struct vb2_buf_ops { * the V4L2_BUF_TYPE_* in include/uapi/linux/videodev2.h * @io_modes: supported io methods (see vb2_io_modes enum) * @dev: device to use for the default allocation context if the driver - * doesn't fill in the @alloc_ctx array. + * doesn't fill in the @alloc_devs array. * @dma_attrs: DMA attributes to use for the DMA. May be NULL. * @fileio_read_once: report EOF after reading the first buffer * @fileio_write_immediately: queue buffer after each write() call @@ -449,7 +449,7 @@ struct vb2_buf_ops { * @done_list: list of buffers ready to be dequeued to userspace * @done_lock: lock to protect done_list list * @done_wq: waitqueue for processes waiting for buffers ready to be dequeued - * @alloc_ctx: memory type/allocator-specific contexts for each plane + * @alloc_devs: memory type/allocator-specific per-plane device * @streaming: current streaming state * @start_streaming_called: start_streaming() was called successfully and we * started streaming. @@ -503,7 +503,7 @@ struct vb2_queue { spinlock_t done_lock; wait_queue_head_t done_wq; - void *alloc_ctx[VB2_MAX_PLANES]; + struct device *alloc_devs[VB2_MAX_PLANES]; unsigned int streaming:1; unsigned int start_streaming_called:1; diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index 5bdd4a4072e5..df2aabee3401 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h @@ -26,8 +26,6 @@ vb2_dma_contig_plane_dma_addr(struct vb2_buffer *vb, unsigned int plane_no) return *addr; } -void *vb2_dma_contig_init_ctx(struct device *dev); -void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); void vb2_dma_contig_clear_max_seg_size(struct device *dev); diff --git a/include/media/videobuf2-dma-sg.h b/include/media/videobuf2-dma-sg.h index 8d1083f83c3d..52afa0e2bb17 100644 --- a/include/media/videobuf2-dma-sg.h +++ b/include/media/videobuf2-dma-sg.h @@ -21,9 +21,6 @@ static inline struct sg_table *vb2_dma_sg_plane_desc( return (struct sg_table *)vb2_plane_cookie(vb, plane_no); } -void *vb2_dma_sg_init_ctx(struct device *dev); -void vb2_dma_sg_cleanup_ctx(void *alloc_ctx); - extern const struct vb2_mem_ops vb2_dma_sg_memops; #endif diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index 5f91d76260ff..93b76c3220fd 100644 --- a/samples/v4l/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c @@ -163,7 +163,7 @@ static irqreturn_t skeleton_irq(int irq, void *dev_id) */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct skeleton *skel = vb2_get_drv_priv(vq); -- cgit v1.2.3 From 12655445a2adc292db3352bbe80e43bd243517aa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 30 Jun 2016 07:01:41 -0300 Subject: [media] cec.h/cec-funcs.h: add option to use BSD license Like the videodev2.h and other headers, explicitly allow these headers to be used with the BSD license. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 16 ++++++++++++++++ include/linux/cec.h | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'include') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h index 8ee1029b9b74..19486009693a 100644 --- a/include/linux/cec-funcs.h +++ b/include/linux/cec-funcs.h @@ -7,6 +7,22 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * + * Alternatively you can redistribute this file under the terms of the + * BSD license as stated below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * * 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 diff --git a/include/linux/cec.h b/include/linux/cec.h index 40924e79465d..6678afe26844 100644 --- a/include/linux/cec.h +++ b/include/linux/cec.h @@ -7,6 +7,22 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * + * Alternatively you can redistribute this file under the terms of the + * BSD license as stated below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * * 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 -- cgit v1.2.3 From 0cb1f1e44cf5b013dd0991f509e332ac77ce2ddd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Jul 2016 05:49:26 -0300 Subject: [media] cec-funcs.h: add length checks Add msg->len sanity checks to fix static checker warning: include/linux/cec-funcs.h:1154 cec_ops_set_osd_string() warn: setting length 'msg->len - 3' to negative one Signed-off-by: Hans Verkuil Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h index 19486009693a..8d217ce53034 100644 --- a/include/linux/cec-funcs.h +++ b/include/linux/cec-funcs.h @@ -788,7 +788,7 @@ static inline void cec_msg_set_timer_program_title(struct cec_msg *msg, static inline void cec_ops_set_timer_program_title(const struct cec_msg *msg, char *prog_title) { - unsigned int len = msg->len - 2; + unsigned int len = msg->len > 2 ? msg->len - 2 : 0; if (len > 14) len = 14; @@ -1167,7 +1167,7 @@ static inline void cec_ops_set_osd_string(const struct cec_msg *msg, __u8 *disp_ctl, char *osd) { - unsigned int len = msg->len - 3; + unsigned int len = msg->len > 3 ? msg->len - 3 : 0; *disp_ctl = msg->msg[2]; if (len > 13) @@ -1192,7 +1192,7 @@ static inline void cec_msg_set_osd_name(struct cec_msg *msg, const char *name) static inline void cec_ops_set_osd_name(const struct cec_msg *msg, char *name) { - unsigned int len = msg->len - 2; + unsigned int len = msg->len > 2 ? msg->len - 2 : 0; if (len > 14) len = 14; -- cgit v1.2.3 From 0c1f8569942695b7a2735301efe45ecd69e2a41f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Jul 2016 05:36:26 -0300 Subject: [media] cec-funcs.h: add missing const modifier The cec_ops_* functions never touch cec_msg, so mark it as const. This was done for some of the cec_ops_ functions, but not all. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h index 8d217ce53034..455f9df86c43 100644 --- a/include/linux/cec-funcs.h +++ b/include/linux/cec-funcs.h @@ -420,7 +420,7 @@ static inline void cec_msg_timer_status(struct cec_msg *msg, } } -static inline void cec_ops_timer_status(struct cec_msg *msg, +static inline void cec_ops_timer_status(const struct cec_msg *msg, __u8 *timer_overlap_warning, __u8 *media_info, __u8 *prog_info, @@ -455,7 +455,7 @@ static inline void cec_msg_timer_cleared_status(struct cec_msg *msg, msg->msg[2] = timer_cleared_status; } -static inline void cec_ops_timer_cleared_status(struct cec_msg *msg, +static inline void cec_ops_timer_cleared_status(const struct cec_msg *msg, __u8 *timer_cleared_status) { *timer_cleared_status = msg->msg[2]; @@ -491,7 +491,7 @@ static inline void cec_msg_clear_analogue_timer(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; } -static inline void cec_ops_clear_analogue_timer(struct cec_msg *msg, +static inline void cec_ops_clear_analogue_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -541,7 +541,7 @@ static inline void cec_msg_clear_digital_timer(struct cec_msg *msg, cec_set_digital_service_id(msg->msg + 9, digital); } -static inline void cec_ops_clear_digital_timer(struct cec_msg *msg, +static inline void cec_ops_clear_digital_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -592,7 +592,7 @@ static inline void cec_msg_clear_ext_timer(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; } -static inline void cec_ops_clear_ext_timer(struct cec_msg *msg, +static inline void cec_ops_clear_ext_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -647,7 +647,7 @@ static inline void cec_msg_set_analogue_timer(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; } -static inline void cec_ops_set_analogue_timer(struct cec_msg *msg, +static inline void cec_ops_set_analogue_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -697,7 +697,7 @@ static inline void cec_msg_set_digital_timer(struct cec_msg *msg, cec_set_digital_service_id(msg->msg + 9, digital); } -static inline void cec_ops_set_digital_timer(struct cec_msg *msg, +static inline void cec_ops_set_digital_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -748,7 +748,7 @@ static inline void cec_msg_set_ext_timer(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; } -static inline void cec_ops_set_ext_timer(struct cec_msg *msg, +static inline void cec_ops_set_ext_timer(const struct cec_msg *msg, __u8 *day, __u8 *month, __u8 *start_hr, @@ -853,7 +853,7 @@ static inline void cec_msg_set_menu_language(struct cec_msg *msg, memcpy(msg->msg + 2, language, 3); } -static inline void cec_ops_set_menu_language(struct cec_msg *msg, +static inline void cec_ops_set_menu_language(const struct cec_msg *msg, char *language) { memcpy(language, msg->msg + 2, 3); @@ -926,7 +926,7 @@ static inline void cec_msg_deck_control(struct cec_msg *msg, msg->msg[2] = deck_control_mode; } -static inline void cec_ops_deck_control(struct cec_msg *msg, +static inline void cec_ops_deck_control(const struct cec_msg *msg, __u8 *deck_control_mode) { *deck_control_mode = msg->msg[2]; @@ -940,7 +940,7 @@ static inline void cec_msg_deck_status(struct cec_msg *msg, msg->msg[2] = deck_info; } -static inline void cec_ops_deck_status(struct cec_msg *msg, +static inline void cec_ops_deck_status(const struct cec_msg *msg, __u8 *deck_info) { *deck_info = msg->msg[2]; @@ -956,7 +956,7 @@ static inline void cec_msg_give_deck_status(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_DECK_STATUS : 0; } -static inline void cec_ops_give_deck_status(struct cec_msg *msg, +static inline void cec_ops_give_deck_status(const struct cec_msg *msg, __u8 *status_req) { *status_req = msg->msg[2]; @@ -970,7 +970,7 @@ static inline void cec_msg_play(struct cec_msg *msg, msg->msg[2] = play_mode; } -static inline void cec_ops_play(struct cec_msg *msg, +static inline void cec_ops_play(const struct cec_msg *msg, __u8 *play_mode) { *play_mode = msg->msg[2]; @@ -1035,7 +1035,7 @@ static inline void cec_msg_tuner_device_status(struct cec_msg *msg, &tuner_dev_info->digital); } -static inline void cec_ops_tuner_device_status(struct cec_msg *msg, +static inline void cec_ops_tuner_device_status(const struct cec_msg *msg, struct cec_op_tuner_device_info *tuner_dev_info) { tuner_dev_info->is_analog = msg->len < 10; @@ -1060,7 +1060,7 @@ static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0; } -static inline void cec_ops_give_tuner_device_status(struct cec_msg *msg, +static inline void cec_ops_give_tuner_device_status(const struct cec_msg *msg, __u8 *status_req) { *status_req = msg->msg[2]; @@ -1079,7 +1079,7 @@ static inline void cec_msg_select_analogue_service(struct cec_msg *msg, msg->msg[5] = bcast_system; } -static inline void cec_ops_select_analogue_service(struct cec_msg *msg, +static inline void cec_ops_select_analogue_service(const struct cec_msg *msg, __u8 *ana_bcast_type, __u16 *ana_freq, __u8 *bcast_system) @@ -1097,7 +1097,7 @@ static inline void cec_msg_select_digital_service(struct cec_msg *msg, cec_set_digital_service_id(msg->msg + 2, digital); } -static inline void cec_ops_select_digital_service(struct cec_msg *msg, +static inline void cec_ops_select_digital_service(const struct cec_msg *msg, struct cec_op_digital_service_id *digital) { cec_get_digital_service_id(msg->msg + 2, digital); @@ -1218,7 +1218,7 @@ static inline void cec_msg_menu_status(struct cec_msg *msg, msg->msg[2] = menu_state; } -static inline void cec_ops_menu_status(struct cec_msg *msg, +static inline void cec_ops_menu_status(const struct cec_msg *msg, __u8 *menu_state) { *menu_state = msg->msg[2]; @@ -1234,7 +1234,7 @@ static inline void cec_msg_menu_request(struct cec_msg *msg, msg->reply = reply ? CEC_MSG_MENU_STATUS : 0; } -static inline void cec_ops_menu_request(struct cec_msg *msg, +static inline void cec_ops_menu_request(const struct cec_msg *msg, __u8 *menu_req) { *menu_req = msg->msg[2]; @@ -1284,7 +1284,7 @@ static inline void cec_msg_user_control_pressed(struct cec_msg *msg, } } -static inline void cec_ops_user_control_pressed(struct cec_msg *msg, +static inline void cec_ops_user_control_pressed(const struct cec_msg *msg, struct cec_op_ui_command *ui_cmd) { ui_cmd->ui_cmd = msg->msg[2]; -- cgit v1.2.3 From 9ad52b4db79d168867a2ca105eca00fb9cb28fe5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Jul 2016 05:52:34 -0300 Subject: [media] cec-funcs.h: add missing 'reply' for short audio descriptor The cec_msg_request_short_audio_descriptor function was missing the reply argument. That's needed if you want the framework to wait for the reply message. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/linux/cec-funcs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h index 455f9df86c43..82c3d3b7269d 100644 --- a/include/linux/cec-funcs.h +++ b/include/linux/cec-funcs.h @@ -1494,6 +1494,7 @@ static inline void cec_ops_report_short_audio_descriptor(const struct cec_msg *m } static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg, + bool reply, __u8 num_descriptors, const __u8 *audio_format_id, const __u8 *audio_format_code) @@ -1504,6 +1505,7 @@ static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg, num_descriptors = 4; msg->len = 2 + num_descriptors; msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR; + msg->reply = reply ? CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR : 0; for (i = 0; i < num_descriptors; i++) msg->msg[2 + i] = (audio_format_id[i] << 6) | (audio_format_code[i] & 0x3f); -- cgit v1.2.3 From a4d020e97d8e65d57061677c15c89e99609d0b37 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Fri, 20 May 2016 12:08:35 -0300 Subject: [media] Convert Wideview WT220 DVB USB driver to rc-core Converts the dtt200u DVB USB driver over to the rc-core infrastructure for its handling of IR remotes. This device can receive generic NEC / NEC Extended signals and the switch to the newer core enables the easy use of tools such as ir-keytable to modify the active key map. Signed-off-by: Jonathan McDowell Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-dtt200u.c | 59 ++++++++++++++++++++++++++++ drivers/media/usb/dvb-usb/dtt200u.c | 74 +++++++++++++++++------------------ include/media/rc-map.h | 1 + 4 files changed, 98 insertions(+), 37 deletions(-) create mode 100644 drivers/media/rc/keymaps/rc-dtt200u.c (limited to 'include') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 9cffcc61fdca..d7b13fae1267 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-dm1105-nec.o \ rc-dntv-live-dvb-t.o \ rc-dntv-live-dvbt-pro.o \ + rc-dtt200u.o \ rc-dvbsky.o \ rc-em-terratec.o \ rc-encore-enltv2.o \ diff --git a/drivers/media/rc/keymaps/rc-dtt200u.c b/drivers/media/rc/keymaps/rc-dtt200u.c new file mode 100644 index 000000000000..25650e9e4664 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-dtt200u.c @@ -0,0 +1,59 @@ +/* Keytable for Wideview WT-220U. + * + * Copyright (c) 2016 Jonathan McDowell + * + * 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. + */ + +#include +#include + +/* key list for the tiny remote control (Yakumo, don't know about the others) */ +static struct rc_map_table dtt200u_table[] = { + { 0x8001, KEY_MUTE }, + { 0x8002, KEY_CHANNELDOWN }, + { 0x8003, KEY_VOLUMEDOWN }, + { 0x8004, KEY_1 }, + { 0x8005, KEY_2 }, + { 0x8006, KEY_3 }, + { 0x8007, KEY_4 }, + { 0x8008, KEY_5 }, + { 0x8009, KEY_6 }, + { 0x800a, KEY_7 }, + { 0x800c, KEY_ZOOM }, + { 0x800d, KEY_0 }, + { 0x800e, KEY_SELECT }, + { 0x8012, KEY_POWER }, + { 0x801a, KEY_CHANNELUP }, + { 0x801b, KEY_8 }, + { 0x801e, KEY_VOLUMEUP }, + { 0x801f, KEY_9 }, +}; + +static struct rc_map_list dtt200u_map = { + .map = { + .scan = dtt200u_table, + .size = ARRAY_SIZE(dtt200u_table), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_DTT200U, + } +}; + +static int __init init_rc_map_dtt200u(void) +{ + return rc_map_register(&dtt200u_map); +} + +static void __exit exit_rc_map_dtt200u(void) +{ + rc_map_unregister(&dtt200u_map); +} + +module_init(init_rc_map_dtt200u) +module_exit(exit_rc_map_dtt200u) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonathan McDowell "); diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c index ca3b69aa9688..be633ece4194 100644 --- a/drivers/media/usb/dvb-usb/dtt200u.c +++ b/drivers/media/usb/dvb-usb/dtt200u.c @@ -55,36 +55,36 @@ static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, return dvb_usb_generic_write(adap->dev, b_pid, 4); } -/* remote control */ -/* key list for the tiny remote control (Yakumo, don't know about the others) */ -static struct rc_map_table rc_map_dtt200u_table[] = { - { 0x8001, KEY_MUTE }, - { 0x8002, KEY_CHANNELDOWN }, - { 0x8003, KEY_VOLUMEDOWN }, - { 0x8004, KEY_1 }, - { 0x8005, KEY_2 }, - { 0x8006, KEY_3 }, - { 0x8007, KEY_4 }, - { 0x8008, KEY_5 }, - { 0x8009, KEY_6 }, - { 0x800a, KEY_7 }, - { 0x800c, KEY_ZOOM }, - { 0x800d, KEY_0 }, - { 0x800e, KEY_SELECT }, - { 0x8012, KEY_POWER }, - { 0x801a, KEY_CHANNELUP }, - { 0x801b, KEY_8 }, - { 0x801e, KEY_VOLUMEUP }, - { 0x801f, KEY_9 }, -}; - -static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int dtt200u_rc_query(struct dvb_usb_device *d) { u8 key[5],cmd = GET_RC_CODE; + u32 scancode; + dvb_usb_generic_rw(d,&cmd,1,key,5,0); - dvb_usb_nec_rc_key_to_event(d,key,event,state); + if (key[0] == 1) { + scancode = key[1]; + if ((u8) ~key[1] != key[2]) { + /* Extended NEC */ + scancode = scancode << 8; + scancode |= key[2]; + } + scancode = scancode << 8; + scancode |= key[3]; + + /* Check command checksum is ok */ + if ((u8) ~key[3] == key[4]) + rc_keydown(d->rc_dev, RC_TYPE_NEC, scancode, 0); + else + rc_keyup(d->rc_dev); + } else if (key[0] == 2) { + rc_repeat(d->rc_dev); + } else { + rc_keyup(d->rc_dev); + } + if (key[0] != 0) deb_info("key: %*ph\n", 5, key); + return 0; } @@ -164,11 +164,11 @@ static struct dvb_usb_device_properties dtt200u_properties = { }, .power_ctrl = dtt200u_power_ctrl, - .rc.legacy = { + .rc.core = { .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_codes = RC_MAP_DTT200U, .rc_query = dtt200u_rc_query, + .allowed_protos = RC_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -214,11 +214,11 @@ static struct dvb_usb_device_properties wt220u_properties = { }, .power_ctrl = dtt200u_power_ctrl, - .rc.legacy = { + .rc.core = { .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_codes = RC_MAP_DTT200U, .rc_query = dtt200u_rc_query, + .allowed_protos = RC_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -264,11 +264,11 @@ static struct dvb_usb_device_properties wt220u_fc_properties = { }, .power_ctrl = dtt200u_power_ctrl, - .rc.legacy = { + .rc.core = { .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_codes = RC_MAP_DTT200U, .rc_query = dtt200u_rc_query, + .allowed_protos = RC_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, @@ -314,11 +314,11 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { }, .power_ctrl = dtt200u_power_ctrl, - .rc.legacy = { + .rc.core = { .rc_interval = 300, - .rc_map_table = rc_map_dtt200u_table, - .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table), + .rc_codes = RC_MAP_DTT200U, .rc_query = dtt200u_rc_query, + .allowed_protos = RC_BIT_NEC, }, .generic_bulk_ctrl_endpoint = 0x01, diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 6e6557dbeb9f..a459129dd554 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -136,6 +136,7 @@ void rc_map_init(void); #define RC_MAP_DM1105_NEC "rc-dm1105-nec" #define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" #define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t" +#define RC_MAP_DTT200U "rc-dtt200u" #define RC_MAP_DVBSKY "rc-dvbsky" #define RC_MAP_EMPTY "rc-empty" #define RC_MAP_EM_TERRATEC "rc-em-terratec" -- cgit v1.2.3 From f04f2d0e3e9137ec33c24daac686629927b3c839 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 3 Jul 2016 09:02:01 -0300 Subject: [media] v4l2-subdev.h: remove the control subdev ops These are no longer used (finally!), so remove them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/v4l2-controls.txt | 15 ---------- drivers/media/v4l2-core/v4l2-ctrls.c | 45 ----------------------------- include/media/v4l2-ctrls.h | 10 ------- include/media/v4l2-subdev.h | 21 -------------- 4 files changed, 91 deletions(-) (limited to 'include') diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 5e759cab4538..f930b80e9111 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -96,21 +96,6 @@ Basic usage for V4L2 and sub-device drivers Where foo->sd is of type struct v4l2_subdev. - And set all core control ops in your struct v4l2_subdev_core_ops to these - helpers: - - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - - Note: this is a temporary solution only. Once all V4L2 drivers that depend - on subdev drivers are converted to the control framework these helpers will - no longer be needed. - 1.4) Clean up the handler at the end: v4l2_ctrl_handler_free(&foo->ctrl_handler); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 8b321e0aae62..f7abfad9ad23 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -2606,14 +2606,6 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc) } EXPORT_SYMBOL(v4l2_queryctrl); -int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - if (qc->id & (V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND)) - return -EINVAL; - return v4l2_queryctrl(sd->ctrl_handler, qc); -} -EXPORT_SYMBOL(v4l2_subdev_queryctrl); - /* Implement VIDIOC_QUERYMENU */ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) { @@ -2657,13 +2649,6 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) } EXPORT_SYMBOL(v4l2_querymenu); -int v4l2_subdev_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm) -{ - return v4l2_querymenu(sd->ctrl_handler, qm); -} -EXPORT_SYMBOL(v4l2_subdev_querymenu); - - /* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS: @@ -2890,12 +2875,6 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs } EXPORT_SYMBOL(v4l2_g_ext_ctrls); -int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs) -{ - return v4l2_g_ext_ctrls(sd->ctrl_handler, cs); -} -EXPORT_SYMBOL(v4l2_subdev_g_ext_ctrls); - /* Helper function to get a single control */ static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c) { @@ -2941,12 +2920,6 @@ int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control) } EXPORT_SYMBOL(v4l2_g_ctrl); -int v4l2_subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control) -{ - return v4l2_g_ctrl(sd->ctrl_handler, control); -} -EXPORT_SYMBOL(v4l2_subdev_g_ctrl); - s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_ext_control c; @@ -3194,18 +3167,6 @@ int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, } EXPORT_SYMBOL(v4l2_s_ext_ctrls); -int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs) -{ - return try_set_ext_ctrls(NULL, sd->ctrl_handler, cs, false); -} -EXPORT_SYMBOL(v4l2_subdev_try_ext_ctrls); - -int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs) -{ - return try_set_ext_ctrls(NULL, sd->ctrl_handler, cs, true); -} -EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls); - /* Helper function for VIDIOC_S_CTRL compatibility */ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) { @@ -3268,12 +3229,6 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, } EXPORT_SYMBOL(v4l2_s_ctrl); -int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control) -{ - return v4l2_s_ctrl(NULL, sd->ctrl_handler, control); -} -EXPORT_SYMBOL(v4l2_subdev_s_ctrl); - int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val) { lockdep_assert_held(ctrl->handler->lock); diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 5c2ed0cfb841..8b59336b2217 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -903,16 +903,6 @@ int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls * int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c); -/* Helpers for subdevices. If the associated ctrl_handler == NULL then they - will all return -EINVAL. */ -int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc); -int v4l2_subdev_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm); -int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs); -int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs); -int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs); -int v4l2_subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl); -int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl); - /* Can be used as a subscribe_event function that just subscribes control events. */ int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 32fc7a4beb5e..c672efc4f87b 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -143,20 +143,6 @@ struct v4l2_subdev_io_pin_config { * @s_gpio: set GPIO pins. Very simple right now, might need to be extended with * a direction argument if needed. * - * @queryctrl: callback for VIDIOC_QUERYCTL ioctl handler code. - * - * @g_ctrl: callback for VIDIOC_G_CTRL ioctl handler code. - * - * @s_ctrl: callback for VIDIOC_S_CTRL ioctl handler code. - * - * @g_ext_ctrls: callback for VIDIOC_G_EXT_CTRLS ioctl handler code. - * - * @s_ext_ctrls: callback for VIDIOC_S_EXT_CTRLS ioctl handler code. - * - * @try_ext_ctrls: callback for VIDIOC_TRY_EXT_CTRLS ioctl handler code. - * - * @querymenu: callback for VIDIOC_QUERYMENU ioctl handler code. - * * @ioctl: called at the end of ioctl() syscall handler at the V4L2 core. * used to provide support for private ioctls used on the driver. * @@ -190,13 +176,6 @@ struct v4l2_subdev_core_ops { int (*load_fw)(struct v4l2_subdev *sd); int (*reset)(struct v4l2_subdev *sd, u32 val); int (*s_gpio)(struct v4l2_subdev *sd, u32 val); - int (*queryctrl)(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc); - int (*g_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl); - int (*s_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl); - int (*g_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); - int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); - int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); - int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm); long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); #ifdef CONFIG_COMPAT long (*compat_ioctl32)(struct v4l2_subdev *sd, unsigned int cmd, -- cgit v1.2.3 From 8842316bbdcbe7862c0b05839efec5ec4fc73f93 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 28 Jun 2016 11:54:59 -0300 Subject: [media] adv7604/adv7842: drop unused op_656_range and alt_data_sat fields These platform_data fields are no longer needed, drop them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/i2c/adv7604.h | 2 -- include/media/i2c/adv7842.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'include') diff --git a/include/media/i2c/adv7604.h b/include/media/i2c/adv7604.h index a913859bfd30..2e6857dee0cc 100644 --- a/include/media/i2c/adv7604.h +++ b/include/media/i2c/adv7604.h @@ -121,8 +121,6 @@ struct adv76xx_platform_data { /* IO register 0x02 */ unsigned alt_gamma:1; - unsigned op_656_range:1; - unsigned alt_data_sat:1; /* IO register 0x05 */ unsigned blank_data:1; diff --git a/include/media/i2c/adv7842.h b/include/media/i2c/adv7842.h index bc249709bf35..7f53ada9bdf1 100644 --- a/include/media/i2c/adv7842.h +++ b/include/media/i2c/adv7842.h @@ -165,8 +165,6 @@ struct adv7842_platform_data { /* IO register 0x02 */ unsigned alt_gamma:1; - unsigned op_656_range:1; - unsigned alt_data_sat:1; /* IO register 0x05 */ unsigned blank_data:1; -- cgit v1.2.3 From c624b5de5037fab77c75db8272befb2df52a968f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Jul 2016 07:08:58 -0300 Subject: [media] input: serio - add new protocol for the Pulse-Eight USB-CEC Adapter This is for the new pulse8-cec staging driver. Signed-off-by: Hans Verkuil Acked-by: Dmitry Torokhov Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/serio.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/uapi/linux/serio.h b/include/uapi/linux/serio.h index c2ea1698257f..f2447a83ac8d 100644 --- a/include/uapi/linux/serio.h +++ b/include/uapi/linux/serio.h @@ -78,5 +78,6 @@ #define SERIO_TSC40 0x3d #define SERIO_WACOM_IV 0x3e #define SERIO_EGALAX 0x3f +#define SERIO_PULSE8_CEC 0x40 #endif /* _UAPI_SERIO_H */ -- cgit v1.2.3 From 980e0b36b55985dd0a37acd25d29c8f21482db32 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Jul 2016 11:10:42 -0300 Subject: [media] cec: split the timestamp into an rx and tx timestamp When transmitting a message and waiting for a reply it would be good to know the time between when the message was transmitted and when the reply arrived. With only one timestamp field it was set to when the reply arrived and the original transmit time was overwritten. Just taking the timestamp in userspace right before CEC_TRANSMIT is called is not reliable, since the actual transmit can be delayed if the CEC bus is busy. Only the driver can fill this in accurately. So split up the ts field into an rx_ts and a tx_ts. Also move the status fields to after the 'reply' field: they were placed in a strange position and make much more sense when grouped with the other status-related fields. This patch also makes sure that the timestamp is taken as soon as possible. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/cec/cec-adap.c | 24 ++++++++++++------------ include/linux/cec.h | 18 ++++++++++-------- 2 files changed, 22 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/staging/media/cec/cec-adap.c b/drivers/staging/media/cec/cec-adap.c index 3925e0ae62a5..ca34339e3eba 100644 --- a/drivers/staging/media/cec/cec-adap.c +++ b/drivers/staging/media/cec/cec-adap.c @@ -284,7 +284,7 @@ static void cec_data_cancel(struct cec_data *data) list_del_init(&data->list); /* Mark it as an error */ - data->msg.ts = ktime_get_ns(); + data->msg.tx_ts = ktime_get_ns(); data->msg.tx_status = CEC_TX_STATUS_ERROR | CEC_TX_STATUS_MAX_RETRIES; data->attempts = 0; @@ -459,6 +459,7 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, { struct cec_data *data; struct cec_msg *msg; + u64 ts = ktime_get_ns(); dprintk(2, "cec_transmit_done %02x\n", status); mutex_lock(&adap->lock); @@ -477,7 +478,7 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, /* Drivers must fill in the status! */ WARN_ON(status == 0); - msg->ts = ktime_get_ns(); + msg->tx_ts = ts; msg->tx_status |= status; msg->tx_arb_lost_cnt += arb_lost_cnt; msg->tx_nack_cnt += nack_cnt; @@ -561,7 +562,7 @@ static void cec_wait_timeout(struct work_struct *work) /* Mark the message as timed out */ list_del_init(&data->list); - data->msg.ts = ktime_get_ns(); + data->msg.rx_ts = ktime_get_ns(); data->msg.rx_status = CEC_RX_STATUS_TIMEOUT; cec_data_completed(data); unlock: @@ -766,13 +767,14 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) if (WARN_ON(!msg->len || msg->len > CEC_MAX_MSG_SIZE)) return; - mutex_lock(&adap->lock); - msg->ts = ktime_get_ns(); + msg->rx_ts = ktime_get_ns(); msg->rx_status = CEC_RX_STATUS_OK; - msg->tx_status = 0; msg->sequence = msg->reply = msg->timeout = 0; + msg->tx_status = 0; + msg->tx_ts = 0; msg->flags = 0; + mutex_lock(&adap->lock); dprintk(2, "cec_received_msg: %*ph\n", msg->len, msg->msg); /* Check if this message was for us (directed or broadcast). */ @@ -794,7 +796,6 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) */ list_for_each_entry(data, &adap->wait_queue, list) { struct cec_msg *dst = &data->msg; - u8 dst_reply; /* Does the command match? */ if ((abort && cmd != dst->msg[1]) || @@ -807,11 +808,10 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) continue; /* We got a reply */ - msg->sequence = dst->sequence; - msg->tx_status = dst->tx_status; - dst_reply = dst->reply; - *dst = *msg; - dst->reply = dst_reply; + memcpy(dst->msg, msg->msg, msg->len); + dst->len = msg->len; + dst->rx_ts = msg->rx_ts; + dst->rx_status = msg->rx_status; if (abort) { dst->reply = 0; dst->rx_status |= CEC_RX_STATUS_FEATURE_ABORT; diff --git a/include/linux/cec.h b/include/linux/cec.h index 6678afe26844..b3e22893a002 100644 --- a/include/linux/cec.h +++ b/include/linux/cec.h @@ -48,9 +48,10 @@ /** * struct cec_msg - CEC message structure. - * @ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the - * driver. It is set when the message transmission has finished - * and it is set when a message was received. + * @tx_ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the + * driver when the message transmission has finished. + * @rx_ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the + * driver when the message was received. * @len: Length in bytes of the message. * @timeout: The timeout (in ms) that is used to timeout CEC_RECEIVE. * Set to 0 if you want to wait forever. This timeout can also be @@ -61,8 +62,6 @@ * sent. This can be used to track replies to previously sent * messages. * @flags: Set to 0. - * @rx_status: The message receive status bits. Set by the driver. - * @tx_status: The message transmit status bits. Set by the driver. * @msg: The message payload. * @reply: This field is ignored with CEC_RECEIVE and is only used by * CEC_TRANSMIT. If non-zero, then wait for a reply with this @@ -80,6 +79,8 @@ * broadcast, then -EINVAL is returned. * if reply is non-zero, then timeout is set to 1000 (the required * maximum response time). + * @rx_status: The message receive status bits. Set by the driver. + * @tx_status: The message transmit status bits. Set by the driver. * @tx_arb_lost_cnt: The number of 'Arbitration Lost' events. Set by the driver. * @tx_nack_cnt: The number of 'Not Acknowledged' events. Set by the driver. * @tx_low_drive_cnt: The number of 'Low Drive Detected' events. Set by the @@ -87,15 +88,16 @@ * @tx_error_cnt: The number of 'Error' events. Set by the driver. */ struct cec_msg { - __u64 ts; + __u64 tx_ts; + __u64 rx_ts; __u32 len; __u32 timeout; __u32 sequence; __u32 flags; - __u8 rx_status; - __u8 tx_status; __u8 msg[CEC_MAX_MSG_SIZE]; __u8 reply; + __u8 rx_status; + __u8 tx_status; __u8 tx_arb_lost_cnt; __u8 tx_nack_cnt; __u8 tx_low_drive_cnt; -- cgit v1.2.3 From 4f253cecf8cb59816d53267170440efa3e1df018 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 10 Jul 2016 13:34:38 -0300 Subject: [media] redrat3: make hardware timeout configurable Instead of hardcoding a timeout, let userspace change it dynamically by adding a s_timeout ops. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 5 ++++- drivers/media/rc/redrat3.c | 34 ++++++++++++++++++++++++++++++++++ include/media/rc-core.h | 3 +++ 3 files changed, 41 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 5effc65d2947..c3277308a70b 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -292,7 +292,10 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, tmp > dev->max_timeout) return -EINVAL; - dev->timeout = tmp; + if (dev->s_timeout) + ret = dev->s_timeout(dev, tmp); + if (!ret) + dev->timeout = tmp; break; case LIRC_SET_REC_TIMEOUT_REPORTS: diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 1e65f7aa58e2..399f44d89a29 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -475,6 +475,37 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3) return timeout; } +static int redrat3_set_timeout(struct rc_dev *rc_dev, unsigned int timeoutns) +{ + struct redrat3_dev *rr3 = rc_dev->priv; + struct usb_device *udev = rr3->udev; + struct device *dev = rr3->dev; + u32 *timeout; + int ret; + + timeout = kmalloc(sizeof(*timeout), GFP_KERNEL); + if (!timeout) + return -ENOMEM; + + *timeout = cpu_to_be32(redrat3_us_to_len(timeoutns / 1000)); + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), RR3_SET_IR_PARAM, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + RR3_IR_IO_SIG_TIMEOUT, 0, timeout, sizeof(*timeout), + HZ * 25); + dev_dbg(dev, "set ir parm timeout %d ret 0x%02x\n", + be32_to_cpu(*timeout), ret); + + if (ret == sizeof(*timeout)) { + rr3->hw_timeout = timeoutns / 1000; + ret = 0; + } else if (ret >= 0) + ret = -EIO; + + kfree(timeout); + + return ret; +} + static void redrat3_reset(struct redrat3_dev *rr3) { struct usb_device *udev = rr3->udev; @@ -856,7 +887,10 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc->priv = rr3; rc->driver_type = RC_DRIVER_IR_RAW; rc->allowed_protocols = RC_BIT_ALL; + rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT); + rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT); rc->timeout = US_TO_NS(rr3->hw_timeout); + rc->s_timeout = redrat3_set_timeout; rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; rc->driver_name = DRIVER_NAME; diff --git a/include/media/rc-core.h b/include/media/rc-core.h index b6586a91129c..324232cfc08d 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -119,6 +119,7 @@ enum rc_filter_type { * @s_carrier_report: enable carrier reports * @s_filter: set the scancode filter * @s_wakeup_filter: set the wakeup scancode filter + * @s_timeout: set hardware timeout in ns */ struct rc_dev { struct device dev; @@ -174,6 +175,8 @@ struct rc_dev { struct rc_scancode_filter *filter); int (*s_wakeup_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); + int (*s_timeout)(struct rc_dev *dev, + unsigned int timeout); }; #define to_rc_dev(d) container_of(d, struct rc_dev, dev) -- cgit v1.2.3 From 11065f8531ed33d5e847a36ad64231ee599d4996 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Jul 2016 11:40:05 -0300 Subject: [media] cec: limit the size of the transmit queue The size of the transmit queue was unlimited, which meant that in non-blocking mode you could flood the CEC adapter with messages to be transmitted. Limit this to 18 messages. Also print the number of pending transmits and the timeout value in the status debugfs file. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/cec/cec-adap.c | 33 +++++++++++++++++++++++---------- include/media/cec.h | 19 ++++++++++++++----- 2 files changed, 37 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/staging/media/cec/cec-adap.c b/drivers/staging/media/cec/cec-adap.c index cd39a9a82a47..159a89379959 100644 --- a/drivers/staging/media/cec/cec-adap.c +++ b/drivers/staging/media/cec/cec-adap.c @@ -156,10 +156,10 @@ static void cec_queue_msg_fh(struct cec_fh *fh, const struct cec_msg *msg) list_add_tail(&entry->list, &fh->msgs); /* - * if the queue now has more than CEC_MAX_MSG_QUEUE_SZ + * if the queue now has more than CEC_MAX_MSG_RX_QUEUE_SZ * messages, drop the oldest one and send a lost message event. */ - if (fh->queued_msgs == CEC_MAX_MSG_QUEUE_SZ) { + if (fh->queued_msgs == CEC_MAX_MSG_RX_QUEUE_SZ) { list_del(&entry->list); goto lost_msgs; } @@ -278,10 +278,13 @@ static void cec_data_cancel(struct cec_data *data) * It's either the current transmit, or it is a pending * transmit. Take the appropriate action to clear it. */ - if (data->adap->transmitting == data) + if (data->adap->transmitting == data) { data->adap->transmitting = NULL; - else + } else { list_del_init(&data->list); + if (!(data->msg.tx_status & CEC_TX_STATUS_OK)) + data->adap->transmit_queue_sz--; + } /* Mark it as an error */ data->msg.tx_ts = ktime_get_ns(); @@ -405,6 +408,7 @@ int cec_thread_func(void *_adap) data = list_first_entry(&adap->transmit_queue, struct cec_data, list); list_del_init(&data->list); + adap->transmit_queue_sz--; /* Make this the current transmitting message */ adap->transmitting = data; @@ -498,6 +502,7 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, data->attempts--; /* Add the message in front of the transmit queue */ list_add(&data->list, &adap->transmit_queue); + adap->transmit_queue_sz++; goto wake_thread; } @@ -638,6 +643,9 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (!adap->is_configured && !adap->is_configuring) return -ENONET; + if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) + return -EBUSY; + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -682,6 +690,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (fh) list_add_tail(&data->xfer_list, &fh->xfer_list); list_add_tail(&data->list, &adap->transmit_queue); + adap->transmit_queue_sz++; if (!adap->transmitting) wake_up_interruptible(&adap->kthread_waitq); @@ -1621,15 +1630,19 @@ int cec_adap_status(struct seq_file *file, void *priv) adap->monitor_all_cnt); data = adap->transmitting; if (data) - seq_printf(file, "transmitting message: %*ph (reply: %02x)\n", - data->msg.len, data->msg.msg, data->msg.reply); + seq_printf(file, "transmitting message: %*ph (reply: %02x, timeout: %ums)\n", + data->msg.len, data->msg.msg, data->msg.reply, + data->msg.timeout); + seq_printf(file, "pending transmits: %u\n", adap->transmit_queue_sz); list_for_each_entry(data, &adap->transmit_queue, list) { - seq_printf(file, "queued tx message: %*ph (reply: %02x)\n", - data->msg.len, data->msg.msg, data->msg.reply); + seq_printf(file, "queued tx message: %*ph (reply: %02x, timeout: %ums)\n", + data->msg.len, data->msg.msg, data->msg.reply, + data->msg.timeout); } list_for_each_entry(data, &adap->wait_queue, list) { - seq_printf(file, "message waiting for reply: %*ph (reply: %02x)\n", - data->msg.len, data->msg.msg, data->msg.reply); + seq_printf(file, "message waiting for reply: %*ph (reply: %02x, timeout: %ums)\n", + data->msg.len, data->msg.msg, data->msg.reply, + data->msg.timeout); } call_void_op(adap, adap_status, file); diff --git a/include/media/cec.h b/include/media/cec.h index 9a791c08a789..dc7854b855f3 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -126,12 +126,20 @@ struct cec_adap_ops { * With a transfer rate of at most 36 bytes per second this makes 18 messages * per second worst case. * - * We queue at most 3 seconds worth of messages. The CEC specification requires - * that messages are replied to within a second, so 3 seconds should give more - * than enough margin. Since most messages are actually more than 2 bytes, this - * is in practice a lot more than 3 seconds. + * We queue at most 3 seconds worth of received messages. The CEC specification + * requires that messages are replied to within a second, so 3 seconds should + * give more than enough margin. Since most messages are actually more than 2 + * bytes, this is in practice a lot more than 3 seconds. */ -#define CEC_MAX_MSG_QUEUE_SZ (18 * 3) +#define CEC_MAX_MSG_RX_QUEUE_SZ (18 * 3) + +/* + * The transmit queue is limited to 1 second worth of messages (worst case). + * Messages can be transmitted by userspace and kernel space. But for both it + * makes no sense to have a lot of messages queued up. One second seems + * reasonable. + */ +#define CEC_MAX_MSG_TX_QUEUE_SZ (18 * 1) struct cec_adapter { struct module *owner; @@ -141,6 +149,7 @@ struct cec_adapter { struct rc_dev *rc; struct list_head transmit_queue; + unsigned int transmit_queue_sz; struct list_head wait_queue; struct cec_data *transmitting; -- cgit v1.2.3