summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/device_sysfs.c6
-rw-r--r--drivers/android/binder.c105
-rw-r--r--drivers/atm/he.c2
-rw-r--r--drivers/base/power/wakeup.c8
-rw-r--r--drivers/char/applicom.c35
-rw-r--r--drivers/clk/ingenic/cgu.c10
-rw-r--r--drivers/clocksource/exynos_mct.c23
-rw-r--r--drivers/cpufreq/cpufreq.c6
-rw-r--r--drivers/cpufreq/cpufreq_governor.h10
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c8
-rw-r--r--drivers/cpufreq/intel_pstate.c14
-rw-r--r--drivers/cpufreq/pxa2xx-cpufreq.c4
-rw-r--r--drivers/cpufreq/tegra124-cpufreq.c2
-rw-r--r--drivers/crypto/caam/caamalg.c1
-rw-r--r--drivers/dma/at_xdmac.c19
-rw-r--r--drivers/dma/dmatest.c28
-rw-r--r--drivers/dma/sh/usb-dmac.c2
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c7
-rw-r--r--drivers/firmware/iscsi_ibft.c1
-rw-r--r--drivers/gpio/gpio-vf610.c5
-rw-r--r--drivers/gpu/drm/msm/msm_rd.c7
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c9
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys.h3
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c16
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c15
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c19
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_ctl.c8
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_ctl.h6
-rw-r--r--drivers/gpu/drm/msm/sde_hdcp_1x.c10
-rw-r--r--drivers/gpu/drm/radeon/evergreen_cs.c1
-rw-r--r--drivers/gpu/ipu-v3/ipu-common.c8
-rw-r--r--drivers/hwtracing/intel_th/gth.c4
-rw-r--r--drivers/hwtracing/stm/core.c11
-rw-r--r--drivers/i2c/busses/i2c-cadence.c9
-rw-r--r--drivers/i2c/busses/i2c-tegra.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_ud.c1
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c10
-rw-r--r--drivers/input/keyboard/matrix_keypad.c2
-rw-r--r--drivers/input/keyboard/st-keyscan.c4
-rw-r--r--drivers/input/mouse/elan_i2c_core.c1
-rw-r--r--drivers/input/tablet/wacom_serial4.c2
-rw-r--r--drivers/iommu/amd_iommu.c15
-rw-r--r--drivers/irqchip/irq-mmp.c6
-rw-r--r--drivers/isdn/hardware/avm/b1.c2
-rw-r--r--drivers/isdn/i4l/isdn_tty.c8
-rw-r--r--drivers/leds/leds-lp5523.c4
-rw-r--r--drivers/md/raid10.c3
-rw-r--r--drivers/md/raid5.c2
-rw-r--r--drivers/media/Makefile1
-rw-r--r--drivers/media/platform/msm/vidc/msm_v4l2_vidc.c4
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_res_parse.c30
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c14
-rw-r--r--drivers/media/usb/uvc/uvc_video.c8
-rw-r--r--drivers/media/v4l2-core/Kconfig7
-rw-r--r--drivers/media/v4l2loopback-master/Makefile5
-rw-r--r--drivers/media/v4l2loopback-master/v4l2loopback.c2630
-rw-r--r--drivers/media/v4l2loopback-master/v4l2loopback_formats.h419
-rw-r--r--drivers/mfd/ab8500-core.c2
-rw-r--r--drivers/mfd/db8500-prcmu.c4
-rw-r--r--drivers/mfd/mc13xxx-core.c4
-rw-r--r--drivers/mfd/qcom_rpm.c4
-rw-r--r--drivers/mfd/ti_am335x_tscadc.c5
-rw-r--r--drivers/mfd/twl-core.c4
-rw-r--r--drivers/mfd/wm5110-tables.c2
-rw-r--r--drivers/mmc/host/mmc_spi.c1
-rw-r--r--drivers/net/dsa/mv88e6xxx.c2
-rw-r--r--drivers/net/ethernet/altera/altera_msgdma.c3
-rw-r--r--drivers/net/ethernet/altera/altera_tse_main.c4
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl2.c4
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c6
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c6
-rw-r--r--drivers/net/ethernet/hisilicon/hns_mdio.c2
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c2
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c7
-rw-r--r--drivers/net/ethernet/marvell/sky2.c24
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c6
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c4
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c9
-rw-r--r--drivers/net/phy/mdio_bus.c1
-rw-r--r--drivers/net/phy/micrel.c14
-rw-r--r--drivers/net/ppp/pptp.c1
-rw-r--r--drivers/net/team/team.c27
-rw-r--r--drivers/net/team/team_mode_loadbalance.c15
-rw-r--r--drivers/net/vxlan.c13
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c2
-rw-r--r--drivers/net/xen-netback/netback.c10
-rw-r--r--drivers/parport/parport_pc.c2
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson8b.c2
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/regulator/s2mpa01.c10
-rw-r--r--drivers/regulator/s2mps11.c6
-rw-r--r--drivers/s390/block/dasd_eckd.c8
-rw-r--r--drivers/s390/net/qeth_core_main.c15
-rw-r--r--drivers/s390/virtio/virtio_ccw.c4
-rw-r--r--drivers/scsi/csiostor/csio_attr.c2
-rw-r--r--drivers/scsi/isci/init.c14
-rw-r--r--drivers/scsi/libfc/fc_lport.c6
-rw-r--r--drivers/scsi/libiscsi.c6
-rw-r--r--drivers/scsi/libsas/sas_expander.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c2
-rw-r--r--drivers/scsi/ufs/ufshcd.c3
-rw-r--r--drivers/scsi/virtio_scsi.c2
-rw-r--r--drivers/soc/qcom/icnss.c49
-rw-r--r--drivers/soc/qcom/qdsp6v2/voice_svc.c22
-rw-r--r--drivers/soc/qcom/subsystem_notif_virt.c32
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c9
-rw-r--r--drivers/staging/lustre/lnet/lnet/config.c14
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c4
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.c6
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_disk.h1
-rw-r--r--drivers/staging/lustre/lustre/libcfs/debug.c6
-rw-r--r--drivers/staging/lustre/lustre/libcfs/hash.c3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/workitem.c4
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pool.c3
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c10
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c1
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_config.c3
-rw-r--r--drivers/staging/rdma/hfi1/ud.c1
-rw-r--r--drivers/target/iscsi/iscsi_target.c4
-rw-r--r--drivers/thermal/int340x_thermal/processor_thermal_device.c2
-rw-r--r--drivers/tty/serial/8250/8250_pci.c141
-rw-r--r--drivers/tty/serial/fsl_lpuart.c2
-rw-r--r--drivers/usb/dwc3/gadget.c1
-rw-r--r--drivers/usb/gadget/function/f_fs.c3
-rw-r--r--drivers/usb/gadget/function/f_sourcesink.c2
-rw-r--r--drivers/usb/serial/cp210x.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h6
-rw-r--r--drivers/usb/serial/option.c2
134 files changed, 3910 insertions, 331 deletions
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index 1521d9a41d25..a899a7abcf63 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -202,11 +202,15 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
const union acpi_object *of_compatible, *obj;
+ acpi_status status;
int len, count;
int i, nval;
char *c;
- acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ status = acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
/* DT strings are all in lower case */
for (c = buf.pointer; *c != '\0'; c++)
*c = tolower(*c);
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 56bbd494df6a..bff9f44161c2 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -356,6 +356,7 @@ struct binder_error {
* @min_priority: minimum scheduling priority
* (invariant after initialized)
* @inherit_rt: inherit RT scheduling policy from caller
+ * @txn_security_ctx: require sender's security context
* (invariant after initialized)
* @async_todo: list of async work items
* (protected by @proc->inner_lock)
@@ -395,6 +396,7 @@ struct binder_node {
u8 sched_policy:2;
u8 inherit_rt:1;
u8 accept_fds:1;
+ u8 txn_security_ctx:1;
u8 min_priority;
};
bool has_async_transaction;
@@ -652,6 +654,7 @@ struct binder_transaction {
struct binder_priority saved_priority;
bool set_priority_called;
kuid_t sender_euid;
+ binder_uintptr_t security_ctx;
/**
* @lock: protects @from, @to_proc, and @to_thread
*
@@ -1361,6 +1364,7 @@ static struct binder_node *binder_init_node_ilocked(
node->min_priority = to_kernel_prio(node->sched_policy, priority);
node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT);
+ node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX);
spin_lock_init(&node->lock);
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
@@ -2899,6 +2903,8 @@ static void binder_transaction(struct binder_proc *proc,
binder_size_t last_fixup_min_off = 0;
struct binder_context *context = proc->context;
int t_debug_id = atomic_inc_return(&binder_last_id);
+ char *secctx = NULL;
+ u32 secctx_sz = 0;
e = binder_transaction_log_add(&binder_transaction_log);
e->debug_id = t_debug_id;
@@ -3122,6 +3128,20 @@ static void binder_transaction(struct binder_proc *proc,
t->priority = target_proc->default_priority;
}
+ if (target_node && target_node->txn_security_ctx) {
+ u32 secid;
+
+ security_task_getsecid(proc->tsk, &secid);
+ ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
+ if (ret) {
+ return_error = BR_FAILED_REPLY;
+ return_error_param = ret;
+ return_error_line = __LINE__;
+ goto err_get_secctx_failed;
+ }
+ extra_buffers_size += ALIGN(secctx_sz, sizeof(u64));
+ }
+
trace_binder_transaction(reply, t, target_node);
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
@@ -3138,6 +3158,19 @@ static void binder_transaction(struct binder_proc *proc,
t->buffer = NULL;
goto err_binder_alloc_buf_failed;
}
+ if (secctx) {
+ size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
+ ALIGN(tr->offsets_size, sizeof(void *)) +
+ ALIGN(extra_buffers_size, sizeof(void *)) -
+ ALIGN(secctx_sz, sizeof(u64));
+ char *kptr = t->buffer->data + buf_offset;
+
+ t->security_ctx = (uintptr_t)kptr +
+ binder_alloc_get_user_buffer_offset(&target_proc->alloc);
+ memcpy(kptr, secctx, secctx_sz);
+ security_release_secctx(secctx, secctx_sz);
+ secctx = NULL;
+ }
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
@@ -3408,6 +3441,9 @@ err_copy_data_failed:
t->buffer->transaction = NULL;
binder_alloc_free_buf(&target_proc->alloc, t->buffer);
err_binder_alloc_buf_failed:
+ if (secctx)
+ security_release_secctx(secctx, secctx_sz);
+err_get_secctx_failed:
kfree(tcomplete);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
err_alloc_tcomplete_failed:
@@ -4054,11 +4090,13 @@ retry:
while (1) {
uint32_t cmd;
- struct binder_transaction_data tr;
+ struct binder_transaction_data_secctx tr;
+ struct binder_transaction_data *trd = &tr.transaction_data;
struct binder_work *w = NULL;
struct list_head *list = NULL;
struct binder_transaction *t = NULL;
struct binder_thread *t_from;
+ size_t trsize = sizeof(*trd);
binder_inner_proc_lock(proc);
if (!binder_worklist_empty_ilocked(&thread->todo))
@@ -4254,41 +4292,47 @@ retry:
struct binder_node *target_node = t->buffer->target_node;
struct binder_priority node_prio;
- tr.target.ptr = target_node->ptr;
- tr.cookie = target_node->cookie;
+ trd->target.ptr = target_node->ptr;
+ trd->cookie = target_node->cookie;
node_prio.sched_policy = target_node->sched_policy;
node_prio.prio = target_node->min_priority;
binder_transaction_priority(current, t, node_prio,
target_node->inherit_rt);
cmd = BR_TRANSACTION;
} else {
- tr.target.ptr = 0;
- tr.cookie = 0;
+ trd->target.ptr = 0;
+ trd->cookie = 0;
cmd = BR_REPLY;
}
- tr.code = t->code;
- tr.flags = t->flags;
- tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
+ trd->code = t->code;
+ trd->flags = t->flags;
+ trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid);
t_from = binder_get_txn_from(t);
if (t_from) {
struct task_struct *sender = t_from->proc->tsk;
- tr.sender_pid = task_tgid_nr_ns(sender,
- task_active_pid_ns(current));
+ trd->sender_pid =
+ task_tgid_nr_ns(sender,
+ task_active_pid_ns(current));
} else {
- tr.sender_pid = 0;
+ trd->sender_pid = 0;
}
- tr.data_size = t->buffer->data_size;
- tr.offsets_size = t->buffer->offsets_size;
- tr.data.ptr.buffer = (binder_uintptr_t)
+ trd->data_size = t->buffer->data_size;
+ trd->offsets_size = t->buffer->offsets_size;
+ trd->data.ptr.buffer = (binder_uintptr_t)
((uintptr_t)t->buffer->data +
binder_alloc_get_user_buffer_offset(&proc->alloc));
- tr.data.ptr.offsets = tr.data.ptr.buffer +
+ trd->data.ptr.offsets = trd->data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
+ tr.secctx = t->security_ctx;
+ if (t->security_ctx) {
+ cmd = BR_TRANSACTION_SEC_CTX;
+ trsize = sizeof(tr);
+ }
if (put_user(cmd, (uint32_t __user *)ptr)) {
if (t_from)
binder_thread_dec_tmpref(t_from);
@@ -4299,7 +4343,7 @@ retry:
return -EFAULT;
}
ptr += sizeof(uint32_t);
- if (copy_to_user(ptr, &tr, sizeof(tr))) {
+ if (copy_to_user(ptr, &tr, trsize)) {
if (t_from)
binder_thread_dec_tmpref(t_from);
@@ -4308,7 +4352,7 @@ retry:
return -EFAULT;
}
- ptr += sizeof(tr);
+ ptr += trsize;
trace_binder_transaction_received(t);
binder_stat_br(proc, thread, cmd);
@@ -4316,16 +4360,18 @@ retry:
"%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n",
proc->pid, thread->pid,
(cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
- "BR_REPLY",
+ (cmd == BR_TRANSACTION_SEC_CTX) ?
+ "BR_TRANSACTION_SEC_CTX" : "BR_REPLY",
t->debug_id, t_from ? t_from->proc->pid : 0,
t_from ? t_from->pid : 0, cmd,
t->buffer->data_size, t->buffer->offsets_size,
- (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets);
+ (u64)trd->data.ptr.buffer,
+ (u64)trd->data.ptr.offsets);
if (t_from)
binder_thread_dec_tmpref(t_from);
t->buffer->allow_user_free = 1;
- if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
+ if (cmd != BR_REPLY && !(t->flags & TF_ONE_WAY)) {
binder_inner_proc_lock(thread->proc);
t->to_parent = thread->transaction_stack;
t->to_thread = thread;
@@ -4670,7 +4716,8 @@ out:
return ret;
}
-static int binder_ioctl_set_ctx_mgr(struct file *filp)
+static int binder_ioctl_set_ctx_mgr(struct file *filp,
+ struct flat_binder_object *fbo)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
@@ -4699,7 +4746,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
} else {
context->binder_context_mgr_uid = curr_euid;
}
- new_node = binder_new_node(proc, NULL);
+ new_node = binder_new_node(proc, fbo);
if (!new_node) {
ret = -ENOMEM;
goto out;
@@ -4821,8 +4868,20 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
binder_inner_proc_unlock(proc);
break;
}
+ case BINDER_SET_CONTEXT_MGR_EXT: {
+ struct flat_binder_object fbo;
+
+ if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = binder_ioctl_set_ctx_mgr(filp, &fbo);
+ if (ret)
+ goto err;
+ break;
+ }
case BINDER_SET_CONTEXT_MGR:
- ret = binder_ioctl_set_ctx_mgr(filp);
+ ret = binder_ioctl_set_ctx_mgr(filp, NULL);
if (ret)
goto err;
break;
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 0f5cb37636bc..010581e8bee0 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -717,7 +717,7 @@ static int he_init_cs_block_rcm(struct he_dev *he_dev)
instead of '/ 512', use '>> 9' to prevent a call
to divdu3 on x86 platforms
*/
- rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9;
+ rate_cps = (unsigned long long) (1UL << exp) * (man + 512) >> 9;
if (rate_cps < 10)
rate_cps = 10; /* 2.2.1 minimum payload rate is 10 cps */
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 7af116e12e53..37658ff761ed 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -114,7 +114,6 @@ void wakeup_source_drop(struct wakeup_source *ws)
if (!ws)
return;
- del_timer_sync(&ws->timer);
__pm_relax(ws);
}
EXPORT_SYMBOL_GPL(wakeup_source_drop);
@@ -202,6 +201,13 @@ void wakeup_source_remove(struct wakeup_source *ws)
list_del_rcu(&ws->entry);
spin_unlock_irqrestore(&events_lock, flags);
synchronize_srcu(&wakeup_srcu);
+
+ del_timer_sync(&ws->timer);
+ /*
+ * Clear timer.function to make wakeup_source_not_registered() treat
+ * this wakeup source as not registered.
+ */
+ ws->timer.function = NULL;
}
EXPORT_SYMBOL_GPL(wakeup_source_remove);
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 14790304b84b..9fcd51095d13 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -32,6 +32,7 @@
#include <linux/wait.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/nospec.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -386,7 +387,11 @@ static ssize_t ac_write(struct file *file, const char __user *buf, size_t count,
TicCard = st_loc.tic_des_from_pc; /* tic number to send */
IndexCard = NumCard - 1;
- if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO)
+ if (IndexCard >= MAX_BOARD)
+ return -EINVAL;
+ IndexCard = array_index_nospec(IndexCard, MAX_BOARD);
+
+ if (!apbs[IndexCard].RamIO)
return -EINVAL;
#ifdef DEBUG
@@ -697,6 +702,7 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned char IndexCard;
void __iomem *pmem;
int ret = 0;
+ static int warncount = 10;
volatile unsigned char byte_reset_it;
struct st_ram_io *adgl;
void __user *argp = (void __user *)arg;
@@ -711,16 +717,12 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
mutex_lock(&ac_mutex);
IndexCard = adgl->num_card-1;
- if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
- static int warncount = 10;
- if (warncount) {
- printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
- warncount--;
- }
- kfree(adgl);
- mutex_unlock(&ac_mutex);
- return -EINVAL;
- }
+ if (cmd != 6 && IndexCard >= MAX_BOARD)
+ goto err;
+ IndexCard = array_index_nospec(IndexCard, MAX_BOARD);
+
+ if (cmd != 6 && !apbs[IndexCard].RamIO)
+ goto err;
switch (cmd) {
@@ -838,5 +840,16 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
kfree(adgl);
mutex_unlock(&ac_mutex);
return 0;
+
+err:
+ if (warncount) {
+ pr_warn("APPLICOM driver IOCTL, bad board number %d\n",
+ (int)IndexCard + 1);
+ warncount--;
+ }
+ kfree(adgl);
+ mutex_unlock(&ac_mutex);
+ return -EINVAL;
+
}
diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c
index 7cfb7b2a2ed6..8878efb80620 100644
--- a/drivers/clk/ingenic/cgu.c
+++ b/drivers/clk/ingenic/cgu.c
@@ -355,16 +355,16 @@ ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const struct ingenic_cgu_clk_info *clk_info;
- long rate = *parent_rate;
+ unsigned int div = 1;
clk_info = &cgu->clock_info[ingenic_clk->idx];
if (clk_info->type & CGU_CLK_DIV)
- rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
+ div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
else if (clk_info->type & CGU_CLK_FIXDIV)
- rate /= clk_info->fixdiv.div;
+ div = clk_info->fixdiv.div;
- return rate;
+ return DIV_ROUND_UP(*parent_rate, div);
}
static int
@@ -384,7 +384,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
if (clk_info->type & CGU_CLK_DIV) {
div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
- rate = parent_rate / div;
+ rate = DIV_ROUND_UP(parent_rate, div);
if (rate != req_rate)
return -EINVAL;
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index 47f8aafe3344..d65a6036d610 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -379,6 +379,13 @@ static void exynos4_mct_tick_start(unsigned long cycles,
exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
}
+static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
+{
+ /* Clear the MCT tick interrupt */
+ if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1)
+ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
+}
+
static int exynos4_tick_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
@@ -395,6 +402,7 @@ static int set_state_shutdown(struct clock_event_device *evt)
mevt = container_of(evt, struct mct_clock_event_device, evt);
exynos4_mct_tick_stop(mevt);
+ exynos4_mct_tick_clear(mevt);
return 0;
}
@@ -411,8 +419,11 @@ static int set_state_periodic(struct clock_event_device *evt)
return 0;
}
-static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
+static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
{
+ struct mct_clock_event_device *mevt = dev_id;
+ struct clock_event_device *evt = &mevt->evt;
+
/*
* This is for supporting oneshot mode.
* Mct would generate interrupt periodically
@@ -421,16 +432,6 @@ static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
if (!clockevent_state_periodic(&mevt->evt))
exynos4_mct_tick_stop(mevt);
- /* Clear the MCT tick interrupt */
- if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1)
- exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
-}
-
-static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
-{
- struct mct_clock_event_device *mevt = dev_id;
- struct clock_event_device *evt = &mevt->evt;
-
exynos4_mct_tick_clear(mevt);
evt->event_handler(evt);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index b1186b424039..12c5210eabbc 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -580,13 +580,13 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq);
* SYSFS INTERFACE *
*********************************************************************/
static ssize_t show_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
+ struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
}
-static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
+static ssize_t store_boost(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
{
int ret, enable;
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 5621bb03e874..f7b340c27ff2 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -48,11 +48,11 @@ enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};
/* Create attributes */
#define gov_sys_attr_ro(_name) \
-static struct global_attr _name##_gov_sys = \
+static struct kobj_attribute _name##_gov_sys = \
__ATTR(_name, 0444, show_##_name##_gov_sys, NULL)
#define gov_sys_attr_rw(_name) \
-static struct global_attr _name##_gov_sys = \
+static struct kobj_attribute _name##_gov_sys = \
__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
#define gov_pol_attr_ro(_name) \
@@ -74,7 +74,7 @@ __ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
/* Create show/store routines */
#define show_one(_gov, file_name) \
static ssize_t show_##file_name##_gov_sys \
-(struct kobject *kobj, struct attribute *attr, char *buf) \
+(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
{ \
struct _gov##_dbs_tuners *tuners = _gov##_dbs_cdata.gdbs_data->tuners; \
return sprintf(buf, "%u\n", tuners->file_name); \
@@ -90,7 +90,7 @@ static ssize_t show_##file_name##_gov_pol \
#define store_one(_gov, file_name) \
static ssize_t store_##file_name##_gov_sys \
-(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
+(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) \
{ \
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
return store_##file_name(dbs_data, buf, count); \
@@ -254,7 +254,7 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate)
#define declare_show_sampling_rate_min(_gov) \
static ssize_t show_sampling_rate_min_gov_sys \
-(struct kobject *kobj, struct attribute *attr, char *buf) \
+(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
{ \
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index ae65fbc3ceac..44c4a4cec72f 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -1406,7 +1406,7 @@ static ssize_t store_use_migration_notif(
*/
#define show_gov_pol_sys(file_name) \
static ssize_t show_##file_name##_gov_sys \
-(struct kobject *kobj, struct attribute *attr, char *buf) \
+(struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
{ \
return show_##file_name(common_tunables, buf); \
} \
@@ -1419,7 +1419,7 @@ static ssize_t show_##file_name##_gov_pol \
#define store_gov_pol_sys(file_name) \
static ssize_t store_##file_name##_gov_sys \
-(struct kobject *kobj, struct attribute *attr, const char *buf, \
+(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, \
size_t count) \
{ \
return store_##file_name(common_tunables, buf, count); \
@@ -1455,7 +1455,7 @@ show_store_gov_pol_sys(fast_ramp_down);
show_store_gov_pol_sys(enable_prediction);
#define gov_sys_attr_rw(_name) \
-static struct global_attr _name##_gov_sys = \
+static struct kobj_attribute _name##_gov_sys = \
__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
#define gov_pol_attr_rw(_name) \
@@ -1484,7 +1484,7 @@ gov_sys_pol_attr_rw(ignore_hispeed_on_notif);
gov_sys_pol_attr_rw(fast_ramp_down);
gov_sys_pol_attr_rw(enable_prediction);
-static struct global_attr boostpulse_gov_sys =
+static struct kobj_attribute boostpulse_gov_sys =
__ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_sys);
static struct freq_attr boostpulse_gov_pol =
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 88728d997088..15fcf2cac971 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -368,13 +368,13 @@ static void __init intel_pstate_debug_expose_params(void)
/************************** sysfs begin ************************/
#define show_one(file_name, object) \
static ssize_t show_##file_name \
- (struct kobject *kobj, struct attribute *attr, char *buf) \
+ (struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
{ \
return sprintf(buf, "%u\n", limits->object); \
}
static ssize_t show_turbo_pct(struct kobject *kobj,
- struct attribute *attr, char *buf)
+ struct kobj_attribute *attr, char *buf)
{
struct cpudata *cpu;
int total, no_turbo, turbo_pct;
@@ -390,7 +390,7 @@ static ssize_t show_turbo_pct(struct kobject *kobj,
}
static ssize_t show_num_pstates(struct kobject *kobj,
- struct attribute *attr, char *buf)
+ struct kobj_attribute *attr, char *buf)
{
struct cpudata *cpu;
int total;
@@ -401,7 +401,7 @@ static ssize_t show_num_pstates(struct kobject *kobj,
}
static ssize_t show_no_turbo(struct kobject *kobj,
- struct attribute *attr, char *buf)
+ struct kobj_attribute *attr, char *buf)
{
ssize_t ret;
@@ -414,7 +414,7 @@ static ssize_t show_no_turbo(struct kobject *kobj,
return ret;
}
-static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
+static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b,
const char *buf, size_t count)
{
unsigned int input;
@@ -438,7 +438,7 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
return count;
}
-static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
+static ssize_t store_max_perf_pct(struct kobject *a, struct kobj_attribute *b,
const char *buf, size_t count)
{
unsigned int input;
@@ -463,7 +463,7 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
return count;
}
-static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
+static ssize_t store_min_perf_pct(struct kobject *a, struct kobj_attribute *b,
const char *buf, size_t count)
{
unsigned int input;
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index 096377232747..cd0333418d15 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -191,7 +191,7 @@ static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq)
return ret;
}
-static void __init pxa_cpufreq_init_voltages(void)
+static void pxa_cpufreq_init_voltages(void)
{
vcc_core = regulator_get(NULL, "vcc_core");
if (IS_ERR(vcc_core)) {
@@ -207,7 +207,7 @@ static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq)
return 0;
}
-static void __init pxa_cpufreq_init_voltages(void) { }
+static void pxa_cpufreq_init_voltages(void) { }
#endif
static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
index 20bcceb58ccc..8e7deb65fc32 100644
--- a/drivers/cpufreq/tegra124-cpufreq.c
+++ b/drivers/cpufreq/tegra124-cpufreq.c
@@ -141,6 +141,8 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
+ of_node_put(np);
+
return 0;
out_switch_to_pllx:
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index f3307fc38e79..f2d1fea23fbf 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -2081,6 +2081,7 @@ static void init_aead_job(struct aead_request *req,
if (unlikely(req->src != req->dst)) {
if (!edesc->dst_nents) {
dst_dma = sg_dma_address(req->dst);
+ out_options = 0;
} else {
dst_dma = edesc->sec4_sg_dma +
sec4_sg_index *
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 82a7c89caae2..af24c5bf32d6 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -203,6 +203,7 @@ struct at_xdmac_chan {
u32 save_cim;
u32 save_cnda;
u32 save_cndc;
+ u32 irq_status;
unsigned long status;
struct tasklet_struct tasklet;
struct dma_slave_config sconfig;
@@ -1582,8 +1583,8 @@ static void at_xdmac_tasklet(unsigned long data)
struct at_xdmac_desc *desc;
u32 error_mask;
- dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08lx\n",
- __func__, atchan->status);
+ dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08x\n",
+ __func__, atchan->irq_status);
error_mask = AT_XDMAC_CIS_RBEIS
| AT_XDMAC_CIS_WBEIS
@@ -1591,15 +1592,15 @@ static void at_xdmac_tasklet(unsigned long data)
if (at_xdmac_chan_is_cyclic(atchan)) {
at_xdmac_handle_cyclic(atchan);
- } else if ((atchan->status & AT_XDMAC_CIS_LIS)
- || (atchan->status & error_mask)) {
+ } else if ((atchan->irq_status & AT_XDMAC_CIS_LIS)
+ || (atchan->irq_status & error_mask)) {
struct dma_async_tx_descriptor *txd;
- if (atchan->status & AT_XDMAC_CIS_RBEIS)
+ if (atchan->irq_status & AT_XDMAC_CIS_RBEIS)
dev_err(chan2dev(&atchan->chan), "read bus error!!!");
- if (atchan->status & AT_XDMAC_CIS_WBEIS)
+ if (atchan->irq_status & AT_XDMAC_CIS_WBEIS)
dev_err(chan2dev(&atchan->chan), "write bus error!!!");
- if (atchan->status & AT_XDMAC_CIS_ROIS)
+ if (atchan->irq_status & AT_XDMAC_CIS_ROIS)
dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
spin_lock_bh(&atchan->lock);
@@ -1654,7 +1655,7 @@ static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
atchan = &atxdmac->chan[i];
chan_imr = at_xdmac_chan_read(atchan, AT_XDMAC_CIM);
chan_status = at_xdmac_chan_read(atchan, AT_XDMAC_CIS);
- atchan->status = chan_status & chan_imr;
+ atchan->irq_status = chan_status & chan_imr;
dev_vdbg(atxdmac->dma.dev,
"%s: chan%d: imr=0x%x, status=0x%x\n",
__func__, i, chan_imr, chan_status);
@@ -1668,7 +1669,7 @@ static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
at_xdmac_chan_read(atchan, AT_XDMAC_CDA),
at_xdmac_chan_read(atchan, AT_XDMAC_CUBC));
- if (atchan->status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
+ if (atchan->irq_status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
tasklet_schedule(&atchan->tasklet);
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 6796eb1a8a4c..884aecebb249 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -563,11 +563,9 @@ static int dmatest_func(void *data)
srcs[i] = um->addr[i] + src_off;
ret = dma_mapping_error(dev->dev, um->addr[i]);
if (ret) {
- dmaengine_unmap_put(um);
result("src mapping error", total_tests,
src_off, dst_off, len, ret);
- failed_tests++;
- continue;
+ goto error_unmap_continue;
}
um->to_cnt++;
}
@@ -582,11 +580,9 @@ static int dmatest_func(void *data)
DMA_BIDIRECTIONAL);
ret = dma_mapping_error(dev->dev, dsts[i]);
if (ret) {
- dmaengine_unmap_put(um);
result("dst mapping error", total_tests,
src_off, dst_off, len, ret);
- failed_tests++;
- continue;
+ goto error_unmap_continue;
}
um->bidi_cnt++;
}
@@ -611,12 +607,10 @@ static int dmatest_func(void *data)
}
if (!tx) {
- dmaengine_unmap_put(um);
result("prep error", total_tests, src_off,
dst_off, len, ret);
msleep(100);
- failed_tests++;
- continue;
+ goto error_unmap_continue;
}
done->done = false;
@@ -625,12 +619,10 @@ static int dmatest_func(void *data)
cookie = tx->tx_submit(tx);
if (dma_submit_error(cookie)) {
- dmaengine_unmap_put(um);
result("submit error", total_tests, src_off,
dst_off, len, ret);
msleep(100);
- failed_tests++;
- continue;
+ goto error_unmap_continue;
}
dma_async_issue_pending(chan);
@@ -643,16 +635,14 @@ static int dmatest_func(void *data)
dmaengine_unmap_put(um);
result("test timed out", total_tests, src_off, dst_off,
len, 0);
- failed_tests++;
- continue;
+ goto error_unmap_continue;
} else if (status != DMA_COMPLETE) {
dmaengine_unmap_put(um);
result(status == DMA_ERROR ?
"completion error status" :
"completion busy status", total_tests, src_off,
dst_off, len, ret);
- failed_tests++;
- continue;
+ goto error_unmap_continue;
}
dmaengine_unmap_put(um);
@@ -691,6 +681,12 @@ static int dmatest_func(void *data)
verbose_result("test passed", total_tests, src_off,
dst_off, len, 0);
}
+
+ continue;
+
+error_unmap_continue:
+ dmaengine_unmap_put(um);
+ failed_tests++;
}
runtime = ktime_us_delta(ktime_get(), ktime);
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 6682b3eec2b6..cc8fc601ed47 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -700,6 +700,8 @@ static int usb_dmac_runtime_resume(struct device *dev)
#endif /* CONFIG_PM */
static const struct dev_pm_ops usb_dmac_pm = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(usb_dmac_runtime_suspend, usb_dmac_runtime_resume,
NULL)
};
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index 906d0224f50d..228bbf910461 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -88,13 +88,6 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
*/
/*
- * Expose the EFI runtime lock to the UV platform
- */
-#ifdef CONFIG_X86_UV
-extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock);
-#endif
-
-/*
* As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"),
* the EFI specification requires that callers of the time related runtime
* functions serialize with other CMOS accesses in the kernel, as the EFI time
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index 72791232e46b..437c8ef90643 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -513,6 +513,7 @@ static umode_t __init ibft_check_tgt_for(void *data, int type)
case ISCSI_BOOT_TGT_NIC_ASSOC:
case ISCSI_BOOT_TGT_CHAP_TYPE:
rc = S_IRUGO;
+ break;
case ISCSI_BOOT_TGT_NAME:
if (tgt->tgt_name_len)
rc = S_IRUGO;
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 87b950cec6ec..db95c4b99a74 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -227,6 +227,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
struct vf610_gpio_port *port;
struct resource *iores;
struct gpio_chip *gc;
+ int i;
int ret;
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
@@ -265,6 +266,10 @@ static int vf610_gpio_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ /* Mask all GPIO interrupts */
+ for (i = 0; i < gc->ngpio; i++)
+ vf610_gpio_writel(0, port->base + PORT_PCR(i));
+
/* Clear the interrupt status register for all GPIO's */
vf610_gpio_writel(~0, port->base + PORT_ISFR);
diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c
index edf3ff2a7a61..e7e1dc293a5d 100644
--- a/drivers/gpu/drm/msm/msm_rd.c
+++ b/drivers/gpu/drm/msm/msm_rd.c
@@ -112,7 +112,9 @@ static void rd_write(struct msm_rd_state *rd, const void *buf, int sz)
char *fptr = &fifo->buf[fifo->head];
int n;
- wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0);
+ wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0 || !rd->open);
+ if (!rd->open)
+ return;
n = min(sz, circ_space_to_end(&rd->fifo));
memcpy(fptr, ptr, n);
@@ -201,7 +203,10 @@ out:
static int rd_release(struct inode *inode, struct file *file)
{
struct msm_rd_state *rd = inode->i_private;
+
rd->open = false;
+ wake_up_all(&rd->fifo_event);
+
return 0;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index cddbb19c7504..b91fd7f42af3 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -563,6 +563,13 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
sde_enc->cur_master->ops.disable(sde_enc->cur_master);
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+ if (phys && phys->ops.post_disable)
+ phys->ops.post_disable(phys);
+ }
+
sde_enc->cur_master = NULL;
SDE_DEBUG_ENC(sde_enc, "cleared master\n");
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 089083816c50..4653a7fe650b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -106,6 +106,7 @@ struct sde_encoder_phys_ops {
struct drm_display_mode *adjusted_mode);
void (*enable)(struct sde_encoder_phys *encoder);
void (*disable)(struct sde_encoder_phys *encoder);
+ void (*post_disable)(struct sde_encoder_phys *encoder);
int (*atomic_check)(struct sde_encoder_phys *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 76d6fe0e3023..6baaa1652892 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -572,6 +572,19 @@ static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
atomic_read(&phys_enc->vblank_refcount));
}
+static void sde_encoder_phys_cmd_post_disable(
+ struct sde_encoder_phys *phys_enc)
+{
+ if (!phys_enc || !phys_enc->hw_ctl) {
+ SDE_ERROR("invalid encoder %d\n", phys_enc != NULL);
+ return;
+ }
+
+ if (!_sde_encoder_phys_is_ppsplit_slave(phys_enc) &&
+ phys_enc->hw_ctl->ops.clear_intf_cfg)
+ phys_enc->hw_ctl->ops.clear_intf_cfg(phys_enc->hw_ctl);
+}
+
static void sde_encoder_phys_cmd_destroy(struct sde_encoder_phys *phys_enc)
{
struct sde_encoder_phys_cmd *cmd_enc =
@@ -648,6 +661,7 @@ static void sde_encoder_phys_cmd_init_ops(
ops->mode_fixup = sde_encoder_phys_cmd_mode_fixup;
ops->enable = sde_encoder_phys_cmd_enable;
ops->disable = sde_encoder_phys_cmd_disable;
+ ops->post_disable = sde_encoder_phys_cmd_post_disable;
ops->destroy = sde_encoder_phys_cmd_destroy;
ops->get_hw_resources = sde_encoder_phys_cmd_get_hw_resources;
ops->control_vblank_irq = sde_encoder_phys_cmd_control_vblank_irq;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 8db77f2c60e8..0d5cc47294ab 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -835,6 +835,18 @@ static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
phys_enc->enable_state = SDE_ENC_DISABLED;
}
+static void sde_encoder_phys_vid_post_disable(
+ struct sde_encoder_phys *phys_enc)
+{
+ if (!phys_enc || !phys_enc->hw_ctl) {
+ SDE_ERROR("invalid encoder %d\n", phys_enc != NULL);
+ return;
+ }
+
+ if (phys_enc->hw_ctl->ops.clear_intf_cfg)
+ phys_enc->hw_ctl->ops.clear_intf_cfg(phys_enc->hw_ctl);
+}
+
static void sde_encoder_phys_vid_handle_post_kickoff(
struct sde_encoder_phys *phys_enc)
{
@@ -890,6 +902,7 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
ops->mode_fixup = sde_encoder_phys_vid_mode_fixup;
ops->enable = sde_encoder_phys_vid_enable;
ops->disable = sde_encoder_phys_vid_disable;
+ ops->post_disable = sde_encoder_phys_vid_post_disable;
ops->destroy = sde_encoder_phys_vid_destroy;
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
ops->control_vblank_irq = sde_encoder_phys_vid_control_vblank_irq;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 65b16419fcec..38bd11bf162e 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -767,6 +767,22 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc)
}
/**
+ * sde_encoder_phys_wb_post_disable - post disable writeback encoder
+ * @phys_enc: Pointer to physical encoder
+ */
+static void sde_encoder_phys_wb_post_disable(
+ struct sde_encoder_phys *phys_enc)
+{
+ if (!phys_enc || !phys_enc->hw_ctl) {
+ SDE_ERROR("invalid encoder %d\n", phys_enc != NULL);
+ return;
+ }
+
+ if (phys_enc->hw_ctl->ops.clear_intf_cfg)
+ phys_enc->hw_ctl->ops.clear_intf_cfg(phys_enc->hw_ctl);
+}
+
+/**
* sde_encoder_phys_wb_get_hw_resources - get hardware resources
* @phys_enc: Pointer to physical encoder
* @hw_res: Pointer to encoder resources
@@ -903,6 +919,7 @@ static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops)
ops->mode_set = sde_encoder_phys_wb_mode_set;
ops->enable = sde_encoder_phys_wb_enable;
ops->disable = sde_encoder_phys_wb_disable;
+ ops->post_disable = sde_encoder_phys_wb_post_disable;
ops->destroy = sde_encoder_phys_wb_destroy;
ops->atomic_check = sde_encoder_phys_wb_atomic_check;
ops->get_hw_resources = sde_encoder_phys_wb_get_hw_resources;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index e9fb9a2e3183..7cd7b5f234b8 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -500,6 +500,13 @@ static void sde_hw_ctl_intf_cfg(struct sde_hw_ctl *ctx,
SDE_REG_WRITE(c, CTL_TOP, intf_cfg);
}
+static void sde_hw_ctl_clear_intf_cfg(struct sde_hw_ctl *ctx)
+{
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+ SDE_REG_WRITE(c, CTL_TOP, 0);
+}
+
static inline u32 sde_hw_ctl_read_ctl_top_for_splash(struct sde_hw_ctl *ctx)
{
struct sde_hw_blk_reg_map *c;
@@ -542,6 +549,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
ops->get_flush_register = sde_hw_ctl_get_flush_register;
ops->trigger_start = sde_hw_ctl_trigger_start;
ops->setup_intf_cfg = sde_hw_ctl_intf_cfg;
+ ops->clear_intf_cfg = sde_hw_ctl_clear_intf_cfg;
ops->reset = sde_hw_ctl_reset_control;
ops->wait_reset_status = sde_hw_ctl_wait_reset_status;
ops->clear_all_blendstages = sde_hw_ctl_clear_all_blendstages;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index ef4ddfafa566..6711bf227fe9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -109,6 +109,12 @@ struct sde_hw_ctl_ops {
void (*setup_intf_cfg)(struct sde_hw_ctl *ctx,
struct sde_hw_intf_cfg *cfg);
+ /**
+ * Clear ctl_path interface config
+ * @ctx : ctl path ctx pointer
+ */
+ void (*clear_intf_cfg)(struct sde_hw_ctl *ctx);
+
int (*reset)(struct sde_hw_ctl *c);
/*
diff --git a/drivers/gpu/drm/msm/sde_hdcp_1x.c b/drivers/gpu/drm/msm/sde_hdcp_1x.c
index ddbe54f6280f..49ce37393e81 100644
--- a/drivers/gpu/drm/msm/sde_hdcp_1x.c
+++ b/drivers/gpu/drm/msm/sde_hdcp_1x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1310,10 +1310,6 @@ static int sde_hdcp_1x_authentication_part2(struct sde_hdcp_1x *hdcp)
}
do {
- rc = sde_hdcp_1x_transfer_v_h(hdcp);
- if (rc)
- goto error;
-
/*
* Do not proceed further if no device connected
* If no downstream devices are attached to the repeater
@@ -1325,6 +1321,10 @@ static int sde_hdcp_1x_authentication_part2(struct sde_hdcp_1x *hdcp)
goto error;
}
+ rc = sde_hdcp_1x_transfer_v_h(hdcp);
+ if (rc)
+ goto error;
+
rc = sde_hdcp_1x_write_ksv_fifo(hdcp);
} while (--v_retry && rc);
error:
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 46f87d4aaf31..782fee330b4c 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -1299,6 +1299,7 @@ static int evergreen_cs_handle_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
return -EINVAL;
}
ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
+ break;
case CB_TARGET_MASK:
track->cb_target_mask = radeon_get_ib_value(p, idx);
track->cb_dirty = true;
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 5030cba4a581..df295a0ce87d 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -746,8 +746,8 @@ static struct ipu_devtype ipu_type_imx51 = {
.cpmem_ofs = 0x1f000000,
.srm_ofs = 0x1f040000,
.tpm_ofs = 0x1f060000,
- .csi0_ofs = 0x1f030000,
- .csi1_ofs = 0x1f038000,
+ .csi0_ofs = 0x1e030000,
+ .csi1_ofs = 0x1e038000,
.ic_ofs = 0x1e020000,
.disp0_ofs = 0x1e040000,
.disp1_ofs = 0x1e048000,
@@ -762,8 +762,8 @@ static struct ipu_devtype ipu_type_imx53 = {
.cpmem_ofs = 0x07000000,
.srm_ofs = 0x07040000,
.tpm_ofs = 0x07060000,
- .csi0_ofs = 0x07030000,
- .csi1_ofs = 0x07038000,
+ .csi0_ofs = 0x06030000,
+ .csi1_ofs = 0x06038000,
.ic_ofs = 0x06020000,
.disp0_ofs = 0x06040000,
.disp1_ofs = 0x06048000,
diff --git a/drivers/hwtracing/intel_th/gth.c b/drivers/hwtracing/intel_th/gth.c
index 2dc5378ccd3a..eb43943cdf07 100644
--- a/drivers/hwtracing/intel_th/gth.c
+++ b/drivers/hwtracing/intel_th/gth.c
@@ -591,11 +591,15 @@ static void intel_th_gth_unassign(struct intel_th_device *thdev,
{
struct gth_device *gth = dev_get_drvdata(&thdev->dev);
int port = othdev->output.port;
+ int master;
spin_lock(&gth->gth_lock);
othdev->output.port = -1;
othdev->output.active = false;
gth->output[port].output = NULL;
+ for (master = 0; master < TH_CONFIGURABLE_MASTERS; master++)
+ if (gth->master[master] == port)
+ gth->master[master] = -1;
spin_unlock(&gth->gth_lock);
}
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 129fcf1c06d9..b862b8e3f579 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -251,6 +251,9 @@ static int find_free_channels(unsigned long *bitmap, unsigned int start,
;
if (i == width)
return pos;
+
+ /* step over [pos..pos+i) to continue search */
+ pos += i;
}
return -1;
@@ -526,7 +529,7 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg)
{
struct stm_device *stm = stmf->stm;
struct stp_policy_id *id;
- int ret = -EINVAL;
+ int ret = -EINVAL, wlimit = 1;
u32 size;
if (stmf->output.nr_chans)
@@ -554,8 +557,10 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg)
if (id->__reserved_0 || id->__reserved_1)
goto err_free;
- if (id->width < 1 ||
- id->width > PAGE_SIZE / stm->data->sw_mmiosz)
+ if (stm->data->sw_mmiosz)
+ wlimit = PAGE_SIZE / stm->data->sw_mmiosz;
+
+ if (id->width < 1 || id->width > wlimit)
goto err_free;
ret = stm_file_assign(stmf, id->id, id->width);
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 84deed6571bd..6d32e6da3110 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -378,8 +378,10 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
*/
- if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
+ if ((id->recv_count > CDNS_I2C_FIFO_DEPTH) || id->bus_hold_flag)
ctrl_reg |= CDNS_I2C_CR_HOLD;
+ else
+ ctrl_reg = ctrl_reg & ~CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
@@ -436,8 +438,11 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
*/
- if (id->send_count > CDNS_I2C_FIFO_DEPTH)
+ if ((id->send_count > CDNS_I2C_FIFO_DEPTH) || id->bus_hold_flag)
ctrl_reg |= CDNS_I2C_CR_HOLD;
+ else
+ ctrl_reg = ctrl_reg & ~CDNS_I2C_CR_HOLD;
+
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
/* Clear the interrupts in interrupt status register. */
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index a0522fcc4ff8..1004422dbb10 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -696,7 +696,7 @@ static const struct i2c_algorithm tegra_i2c_algo = {
/* payload size is only 12 bit */
static struct i2c_adapter_quirks tegra_i2c_quirks = {
.max_read_len = 4096,
- .max_write_len = 4096,
+ .max_write_len = 4096 - 12,
};
static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index 59193f67ea78..56bd59bc08b5 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -515,7 +515,6 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr,
opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
wc.ex.imm_data = ohdr->u.ud.imm_data;
wc.wc_flags = IB_WC_WITH_IMM;
- tlen -= sizeof(u32);
} else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
wc.ex.imm_data = 0;
wc.wc_flags = 0;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 1897c4080346..3dbc3ed263c2 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2594,7 +2594,6 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(scmnd->device->host);
struct srp_rdma_ch *ch;
- int i, j;
u8 status;
shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
@@ -2606,15 +2605,6 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
if (status)
return FAILED;
- for (i = 0; i < target->ch_count; i++) {
- ch = &target->ch[i];
- for (j = 0; j < target->req_ring_size; ++j) {
- struct srp_request *req = &ch->req_ring[j];
-
- srp_finish_req(ch, req, scmnd->device, DID_RESET << 16);
- }
- }
-
return SUCCESS;
}
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index c64d87442a62..2e12e31f45c5 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -220,7 +220,7 @@ static void matrix_keypad_stop(struct input_dev *dev)
keypad->stopped = true;
spin_unlock_irq(&keypad->lock);
- flush_work(&keypad->work.work);
+ flush_delayed_work(&keypad->work);
/*
* matrix_keypad_scan() will leave IRQs enabled;
* we should disable them now.
diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c
index de7be4f03d91..ebf9f643d910 100644
--- a/drivers/input/keyboard/st-keyscan.c
+++ b/drivers/input/keyboard/st-keyscan.c
@@ -153,6 +153,8 @@ static int keyscan_probe(struct platform_device *pdev)
input_dev->id.bustype = BUS_HOST;
+ keypad_data->input_dev = input_dev;
+
error = keypad_matrix_key_parse_dt(keypad_data);
if (error)
return error;
@@ -168,8 +170,6 @@ static int keyscan_probe(struct platform_device *pdev)
input_set_drvdata(input_dev, keypad_data);
- keypad_data->input_dev = input_dev;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(keypad_data->base))
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 25ce9047b682..16f5d5660053 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1241,6 +1241,7 @@ static const struct acpi_device_id elan_acpi_id[] = {
{ "ELAN0000", 0 },
{ "ELAN0100", 0 },
{ "ELAN0600", 0 },
+ { "ELAN0601", 0 },
{ "ELAN0602", 0 },
{ "ELAN0605", 0 },
{ "ELAN0608", 0 },
diff --git a/drivers/input/tablet/wacom_serial4.c b/drivers/input/tablet/wacom_serial4.c
index 20ab802461e7..1d46b763aae6 100644
--- a/drivers/input/tablet/wacom_serial4.c
+++ b/drivers/input/tablet/wacom_serial4.c
@@ -187,6 +187,7 @@ enum {
MODEL_DIGITIZER_II = 0x5544, /* UD */
MODEL_GRAPHIRE = 0x4554, /* ET */
MODEL_PENPARTNER = 0x4354, /* CT */
+ MODEL_ARTPAD_II = 0x4B54, /* KT */
};
static void wacom_handle_model_response(struct wacom *wacom)
@@ -245,6 +246,7 @@ static void wacom_handle_model_response(struct wacom *wacom)
wacom->flags = F_HAS_STYLUS2 | F_HAS_SCROLLWHEEL;
break;
+ case MODEL_ARTPAD_II:
case MODEL_DIGITIZER_II:
wacom->dev->name = "Wacom Digitizer II";
wacom->dev->id.version = MODEL_DIGITIZER_II;
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 52c36394dba5..0ad8b7c78a43 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -1982,6 +1982,7 @@ static void do_attach(struct iommu_dev_data *dev_data,
static void do_detach(struct iommu_dev_data *dev_data)
{
+ struct protection_domain *domain = dev_data->domain;
struct amd_iommu *iommu;
u16 alias;
@@ -1997,10 +1998,6 @@ static void do_detach(struct iommu_dev_data *dev_data)
iommu = amd_iommu_rlookup_table[dev_data->devid];
alias = dev_data->alias;
- /* decrease reference counters */
- dev_data->domain->dev_iommu[iommu->index] -= 1;
- dev_data->domain->dev_cnt -= 1;
-
/* Update data structures */
dev_data->domain = NULL;
list_del(&dev_data->list);
@@ -2010,6 +2007,16 @@ static void do_detach(struct iommu_dev_data *dev_data)
/* Flush the DTE entry */
device_flush_dte(dev_data);
+
+ /* Flush IOTLB */
+ domain_flush_tlb_pde(domain);
+
+ /* Wait for the flushes to finish */
+ domain_flush_complete(domain);
+
+ /* decrease reference counters - needs to happen after the flushes */
+ domain->dev_iommu[iommu->index] -= 1;
+ domain->dev_cnt -= 1;
}
/*
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 013fc9659a84..2fe2bcb63a71 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -34,6 +34,9 @@
#define SEL_INT_PENDING (1 << 6)
#define SEL_INT_NUM_MASK 0x3f
+#define MMP2_ICU_INT_ROUTE_PJ4_IRQ (1 << 5)
+#define MMP2_ICU_INT_ROUTE_PJ4_FIQ (1 << 6)
+
struct icu_chip_data {
int nr_irqs;
unsigned int virq_base;
@@ -190,7 +193,8 @@ static struct mmp_intc_conf mmp_conf = {
static struct mmp_intc_conf mmp2_conf = {
.conf_enable = 0x20,
.conf_disable = 0x0,
- .conf_mask = 0x7f,
+ .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ |
+ MMP2_ICU_INT_ROUTE_PJ4_FIQ,
};
static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
index 4d9b195547c5..df2a10157720 100644
--- a/drivers/isdn/hardware/avm/b1.c
+++ b/drivers/isdn/hardware/avm/b1.c
@@ -423,7 +423,7 @@ void b1_parse_version(avmctrl_info *cinfo)
int i, j;
for (j = 0; j < AVM_MAXVERSION; j++)
- cinfo->version[j] = "\0\0" + 1;
+ cinfo->version[j] = "";
for (i = 0, j = 0;
j < AVM_MAXVERSION && i < cinfo->versionlen;
j++, i += cinfo->versionbuf[i] + 1)
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 2175225af742..2da3f5cd0729 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -786,7 +786,7 @@ isdn_tty_suspend(char *id, modem_info *info, atemu *m)
cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
cmd.parm.cmsg.para[4] = 0;
cmd.parm.cmsg.para[5] = l;
- strncpy(&cmd.parm.cmsg.para[6], id, l);
+ strscpy(&cmd.parm.cmsg.para[6], id, l);
cmd.command = CAPI_PUT_MESSAGE;
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
@@ -1459,15 +1459,19 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
modem_info *info = (modem_info *) tty->driver_data;
+ mutex_lock(&modem_info_mutex);
if (!old_termios)
isdn_tty_change_speed(info);
else {
if (tty->termios.c_cflag == old_termios->c_cflag &&
tty->termios.c_ispeed == old_termios->c_ispeed &&
- tty->termios.c_ospeed == old_termios->c_ospeed)
+ tty->termios.c_ospeed == old_termios->c_ospeed) {
+ mutex_unlock(&modem_info_mutex);
return;
+ }
isdn_tty_change_speed(info);
}
+ mutex_unlock(&modem_info_mutex);
}
/*
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index 1d0187f42941..d12370352ae3 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -318,7 +318,9 @@ static int lp5523_init_program_engine(struct lp55xx_chip *chip)
/* Let the programs run for couple of ms and check the engine status */
usleep_range(3000, 6000);
- lp55xx_read(chip, LP5523_REG_STATUS, &status);
+ ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
+ if (ret)
+ return ret;
status &= LP5523_ENG_STATUS_MASK;
if (status != LP5523_ENG_STATUS_MASK) {
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index a3230d760182..24ee310c03cd 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3755,6 +3755,8 @@ static int run(struct mddev *mddev)
set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
mddev->sync_thread = md_register_thread(md_do_sync, mddev,
"reshape");
+ if (!mddev->sync_thread)
+ goto out_free_conf;
}
return 0;
@@ -4442,7 +4444,6 @@ bio_full:
atomic_inc(&r10_bio->remaining);
read_bio->bi_next = NULL;
generic_make_request(read_bio);
- sector_nr += nr_sectors;
sectors_done += nr_sectors;
if (sector_nr <= last)
goto read_more;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index dfe19d74c119..c6133d19ae28 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6973,6 +6973,8 @@ static int run(struct mddev *mddev)
set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
mddev->sync_thread = md_register_thread(md_do_sync, mddev,
"reshape");
+ if (!mddev->sync_thread)
+ goto abort;
}
/* Ok, everything is just fine now */
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 6c7801919b98..9dd447997564 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -32,6 +32,7 @@ endif
obj-$(CONFIG_VIDEO_DEV) += v4l2-core/
obj-$(CONFIG_DVB_CORE) += dvb-core/
+obj-$(CONFIG_VIDEO_DEV) += v4l2loopback-master/
# There are both core and drivers at RC subtree - merge before drivers
obj-y += rc/
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index e81162f3c4ad..a921467e2be4 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,6 +31,7 @@
#include "msm_vidc_resources.h"
#include "venus_boot.h"
#include "vidc_hfi_api.h"
+#include <soc/qcom/boot_stats.h>
#define BASE_DEVICE_NUMBER 32
@@ -608,6 +609,7 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev)
goto err_fail_sub_device_probe;
}
+ place_marker("M - DRIVER Video Ready");
return rc;
err_fail_sub_device_probe:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 59783dc87e5b..925914bc7a6d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -575,6 +575,28 @@ static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
return rc;
}
+static int msm_vidc_check_dcvs_enabled(struct msm_vidc_platform_resources *res)
+{
+ struct platform_device *pdev = res->pdev;
+
+ if (of_find_property(pdev->dev.of_node, "disable-dcvs-enc", NULL)) {
+ /*
+ * disable-dcvs-enc is an optional property.
+ */
+ dprintk(VIDC_DBG, "disable-dcvs-enc\n");
+ msm_vidc_enc_dcvs_mode = false;
+ }
+ if (of_find_property(pdev->dev.of_node, "disable-dcvs-dec", NULL)) {
+ /*
+ * disable-dcvs-dec is an optional property.
+ */
+ dprintk(VIDC_DBG, "disable-dcvs-dec\n");
+ msm_vidc_dec_dcvs_mode = false;
+ }
+
+ return 0;
+}
+
static int msm_vidc_load_dcvs_table(struct msm_vidc_platform_resources *res)
{
int rc = 0;
@@ -1023,6 +1045,12 @@ int read_platform_resources_from_dt(
goto err_load_freq_table;
}
+ rc = msm_vidc_check_dcvs_enabled(res);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to check dcvs flags: %d\n", rc);
+ goto err_load_freq_table;
+ }
+
rc = msm_vidc_load_dcvs_table(res);
if (rc)
dprintk(VIDC_WARN, "Failed to load dcvs table: %d\n", rc);
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 885f689ac870..f2e3fdf385cc 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1019,11 +1019,19 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return -EINVAL;
}
- /* Make sure the terminal type MSB is not null, otherwise it
- * could be confused with a unit.
+ /*
+ * Reject invalid terminal types that would cause issues:
+ *
+ * - The high byte must be non-zero, otherwise it would be
+ * confused with a unit.
+ *
+ * - Bit 15 must be 0, as we use it internally as a terminal
+ * direction flag.
+ *
+ * Other unknown types are accepted.
*/
type = get_unaligned_le16(&buffer[4]);
- if ((type & 0xff00) == 0) {
+ if ((type & 0x7f00) == 0 || (type & 0x8000) != 0) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d INPUT_TERMINAL %d has invalid "
"type 0x%04x, skipping\n", udev->devnum,
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index a4048a04d236..a550dbe36dc5 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -638,6 +638,14 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
if (!uvc_hw_timestamps_param)
return;
+ /*
+ * We will get called from __vb2_queue_cancel() if there are buffers
+ * done but not dequeued by the user, but the sample array has already
+ * been released at that time. Just bail out in that case.
+ */
+ if (!clock->samples)
+ return;
+
spin_lock_irqsave(&clock->lock, flags);
if (clock->count < clock->size)
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index 29b3436d0910..c88290b604a2 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -107,3 +107,10 @@ config VIDEOBUF2_DMA_SG
config VIDEOBUF2_DVB
tristate
select VIDEOBUF2_CORE
+
+config V4L2_LOOPBACK
+ tristate "v4l2loopback driver"
+ ---help---
+ Enable v4l2loopback support, it allows to create
+ "virtual video devices". Normal (v4l2) applications will
+ read these devices as if they were ordinary video devices.
diff --git a/drivers/media/v4l2loopback-master/Makefile b/drivers/media/v4l2loopback-master/Makefile
new file mode 100644
index 000000000000..5c75b88f1558
--- /dev/null
+++ b/drivers/media/v4l2loopback-master/Makefile
@@ -0,0 +1,5 @@
+#
+## Makefile for the V4L2 loopback
+#
+
+obj-$(CONFIG_V4L2_LOOPBACK) += v4l2loopback.o
diff --git a/drivers/media/v4l2loopback-master/v4l2loopback.c b/drivers/media/v4l2loopback-master/v4l2loopback.c
new file mode 100644
index 000000000000..eca57b7aa6fc
--- /dev/null
+++ b/drivers/media/v4l2loopback-master/v4l2loopback.c
@@ -0,0 +1,2630 @@
+/* -*- c-file-style: "linux" -*-*/
+/*
+* v4l2loopback.c -- video4linux2 loopback driver
+*
+* Copyright (C) 2005-2009 Vasily Levin (vasaka@gmail.com)
+* Copyright (C) 2010-2019 IOhannes m zmoelnig (zmoelnig@iem.at)
+* Copyright (C) 2011 Stefan Diewald (stefan.diewald@mytum.de)
+* Copyright (C) 2012 Anton Novikov (random.plant@gmail.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 <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/time.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+# define HAVE__V4L2_DEVICE
+# include <media/v4l2-device.h>
+# define HAVE__V4L2_CTRLS
+# include <media/v4l2-ctrls.h>
+
+#if defined(timer_setup) && defined(from_timer)
+#define HAVE_TIMER_SETUP
+#endif
+
+#define V4L2LOOPBACK_VERSION_CODE KERNEL_VERSION(0, 12, 0)
+#define POLL_CLOSE_EVENT 0x50
+
+MODULE_DESCRIPTION("V4L2 loopback video device");
+MODULE_AUTHOR("Vasily Levin, " \
+ "IOhannes m zmoelnig <zmoelnig@iem.at>," \
+ "Stefan Diewald," \
+ "Anton Novikov" \
+ "et al." \
+ );
+MODULE_LICENSE("GPL");
+
+/*
+ * helpers
+ */
+#define STRINGIFY(s) #s
+#define STRINGIFY2(s) STRINGIFY(s)
+
+#define MARK() \
+ do { if (debug > 1) { \
+ pr_err("%s:%d[%s]\n", __FILE__, __LINE__, __func__); \
+ } } while (0)
+
+/*
+ * compatibility hacks
+ */
+
+#ifndef HAVE__V4L2_CTRLS
+struct v4l2_ctrl_handler {
+ int error;
+};
+struct v4l2_ctrl_config {
+ void *ops;
+ u32 id;
+ const char *name;
+ int type;
+ s32 min;
+ s32 max;
+ u32 step;
+ s32 def;
+};
+int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
+ unsigned nr_of_controls_hint)
+{
+ hdl->error = 0;
+ return 0;
+}
+void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
+{
+}
+void *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_config *conf,
+ void *priv)
+{
+ return NULL;
+}
+#endif /* HAVE__V4L2_CTRLS */
+
+
+#ifndef HAVE__V4L2_DEVICE
+/* dummy v4l2_device struct/functions */
+# define V4L2_DEVICE_NAME_SIZE (20 + 16)
+struct v4l2_device {
+ char name[V4L2_DEVICE_NAME_SIZE];
+ struct v4l2_ctrl_handler *ctrl_handler;
+};
+static inline int v4l2_device_register(void *dev, void *v4l2_dev)
+{
+ return 0;
+}
+static inline void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
+{
+ /* Nothing to return */
+}
+#endif /* HAVE__V4L2_DEVICE */
+
+# define v4l2l_vzalloc vzalloc
+
+
+/* module constants
+ * can be overridden during he build process using something like
+ * make KCPPFLAGS="-DMAX_DEVICES=100"
+ */
+
+
+/* maximum number of v4l2loopback devices that can be created */
+#ifndef MAX_DEVICES
+# define MAX_DEVICES 8
+#endif
+
+/* when a producer is considered to have gone stale */
+#ifndef MAX_TIMEOUT
+# define MAX_TIMEOUT (100 * 1000) /* in msecs */
+#endif
+
+/* max buffers that can be mapped, actually they
+ * are all mapped to max_buffers buffers
+ */
+#ifndef MAX_BUFFERS
+# define MAX_BUFFERS 32
+#endif
+
+/* module parameters */
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "debugging level (higher values == more verbose)");
+
+static int max_buffers = 8;
+module_param(max_buffers, int, S_IRUGO);
+MODULE_PARM_DESC(max_buffers, "how many buffers should be allocated");
+
+/* how many times a device can be opened
+ * the per-module default value can be overridden on a per-device basis using
+ * the /sys/devices interface
+ *
+ * note that max_openers should be at least 2 in order to get a working system:
+ * one opener for the producer and one opener for the consumer
+ * however, we leave that to the user
+ */
+static int max_openers = 10;
+module_param(max_openers, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_openers, "how many users can open loopback device");
+
+
+static int devices = -1;
+module_param(devices, int, 0);
+MODULE_PARM_DESC(devices, "how many devices should be created");
+
+
+static int video_nr[MAX_DEVICES] = { [0 ... (MAX_DEVICES - 1)] = -1 };
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+ "video device numbers (-1=auto, 0=/dev/video0, etc.)");
+
+static char *card_label[MAX_DEVICES];
+module_param_array(card_label, charp, NULL, 0000);
+MODULE_PARM_DESC(card_label, "card labels for every device");
+
+static bool exclusive_caps[MAX_DEVICES] = { [0 ... (MAX_DEVICES - 1)] = 0 };
+module_param_array(exclusive_caps, bool, NULL, 0444);
+/* FIXXME: wording */
+MODULE_PARM_DESC(exclusive_caps,
+ "whether to announce OUTPUT/CAPTURE capabilities exclusively or not");
+
+
+/* format specifications */
+#define V4L2LOOPBACK_SIZE_MIN_WIDTH 48
+#define V4L2LOOPBACK_SIZE_MIN_HEIGHT 32
+#define V4L2LOOPBACK_SIZE_MAX_WIDTH 8192
+#define V4L2LOOPBACK_SIZE_MAX_HEIGHT 8192
+
+#define V4L2LOOPBACK_SIZE_DEFAULT_WIDTH 640
+#define V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT 480
+
+static int max_width = V4L2LOOPBACK_SIZE_MAX_WIDTH;
+module_param(max_width, int, S_IRUGO);
+MODULE_PARM_DESC(max_width, "maximum frame width");
+static int max_height = V4L2LOOPBACK_SIZE_MAX_HEIGHT;
+module_param(max_height, int, S_IRUGO);
+MODULE_PARM_DESC(max_height, "maximum frame height");
+
+
+/* control IDs */
+#ifndef HAVE__V4L2_CTRLS
+# define V4L2LOOPBACK_CID_BASE (V4L2_CID_PRIVATE_BASE)
+#else
+# define V4L2LOOPBACK_CID_BASE (V4L2_CID_USER_BASE | 0xf000)
+#endif
+#define CID_KEEP_FORMAT (V4L2LOOPBACK_CID_BASE + 0)
+#define CID_SUSTAIN_FRAMERATE (V4L2LOOPBACK_CID_BASE + 1)
+#define CID_TIMEOUT (V4L2LOOPBACK_CID_BASE + 2)
+#define CID_TIMEOUT_IMAGE_IO (V4L2LOOPBACK_CID_BASE + 3)
+
+static int v4l2loopback_s_ctrl(struct v4l2_ctrl *ctrl);
+static const struct v4l2_ctrl_ops v4l2loopback_ctrl_ops = {
+ .s_ctrl = v4l2loopback_s_ctrl,
+};
+static const struct v4l2_ctrl_config v4l2loopback_ctrl_keepformat = {
+ .ops = &v4l2loopback_ctrl_ops,
+ .id = CID_KEEP_FORMAT,
+ .name = "keep_format",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 0,
+};
+static const struct v4l2_ctrl_config v4l2loopback_ctrl_sustainframerate = {
+ .ops = &v4l2loopback_ctrl_ops,
+ .id = CID_SUSTAIN_FRAMERATE,
+ .name = "sustain_framerate",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 0,
+};
+static const struct v4l2_ctrl_config v4l2loopback_ctrl_timeout = {
+ .ops = &v4l2loopback_ctrl_ops,
+ .id = CID_TIMEOUT,
+ .name = "timeout",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = MAX_TIMEOUT,
+ .step = 1,
+ .def = 0,
+};
+static const struct v4l2_ctrl_config v4l2loopback_ctrl_timeoutimageio = {
+ .ops = &v4l2loopback_ctrl_ops,
+ .id = CID_TIMEOUT_IMAGE_IO,
+ .name = "timeout_image_io",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 0,
+};
+
+
+/* module structures */
+struct v4l2loopback_private {
+ int devicenr;
+};
+
+/* TODO(vasaka) use typenames which are common to kernel, but first find out if
+ * it is needed
+ */
+/* struct keeping state and settings of loopback device */
+
+struct v4l2l_buffer {
+ struct v4l2_buffer buffer;
+ struct list_head list_head;
+ int use_count;
+};
+
+struct v4l2_loopback_device {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct video_device *vdev;
+ /* pixel and stream format */
+ struct v4l2_pix_format pix_format;
+ struct v4l2_captureparm capture_param;
+ unsigned long frame_jiffies;
+
+ /* ctrls */
+ int keep_format; /* CID_KEEP_FORMAT; stay ready_for_capture even when
+ * all openers close() the device
+ */
+ int sustain_framerate; /* CID_SUSTAIN_FRAMERATE; duplicate
+ * frames to maintain (close to)
+ * nominal framerate
+ */
+
+ /* buffers stuff */
+ u8 *image; /* pointer to actual buffers data */
+ unsigned long int imagesize; /* size of buffers data */
+ int buffers_number; /* should not be big, 4 is a good choice */
+ struct v4l2l_buffer buffers[MAX_BUFFERS]; /* inner driver buffers */
+ int used_buffers; /* number of the actually used buffers */
+ int max_openers; /* how many times can this device be opened */
+
+ int write_position; /* number of last written frame + 1 */
+ struct list_head outbufs_list; /* buffers in output DQBUF order */
+ int bufpos2index[MAX_BUFFERS]; /* mapping of (read/write_position
+ * % used_buffers)
+ * to inner buffer index
+ */
+ long buffer_size;
+
+ /* sustain_framerate stuff */
+ struct timer_list sustain_timer;
+ unsigned int reread_count;
+
+ /* timeout stuff */
+ unsigned long timeout_jiffies; /* CID_TIMEOUT; 0 means disabled */
+ int timeout_image_io; /* CID_TIMEOUT_IMAGE_IO; next opener will
+ * read/write to timeout_image
+ */
+ u8 *timeout_image; /* copy of it will be captured when timeout passes */
+ struct v4l2l_buffer timeout_image_buffer;
+ struct timer_list timeout_timer;
+ int timeout_happened;
+
+ /* sync stuff */
+ atomic_t open_count;
+
+
+ int ready_for_capture;/* set to true when at least one writer opened
+ * device and negotiated format
+ */
+ int ready_for_output; /* set to true when no writer
+ * is currently attached
+ * this differs slightly from !ready_for_capture,
+ * e.g. when using fallback images
+ */
+ int announce_all_caps;/* set to false, if device caps (OUTPUT/CAPTURE)
+ * should only be announced if the resp. "ready"
+ * flag is set; default=TRUE
+ */
+
+ /* Changes for back-channel method */
+ int streamon_complete;
+ int close_complete;
+ int streamon_check;
+ int stream_close_check;
+
+ wait_queue_head_t read_event;
+ wait_queue_head_t write_event;
+ spinlock_t lock;
+};
+
+/* types of opener shows what opener wants to do with loopback */
+enum opener_type {
+ UNNEGOTIATED = 0,
+ READER = 1,
+ WRITER = 2,
+};
+
+/* struct keeping state and type of opener */
+struct v4l2_loopback_opener {
+ enum opener_type type;
+ int vidioc_enum_frameintervals_calls;
+ int read_position; /* number of last processed frame + 1 or
+ * write_position - 1 if reader went out of sync
+ */
+ unsigned int reread_count;
+ struct v4l2_buffer *buffers;
+ int buffers_number; /* should not be big, 4 is a good choice */
+ int timeout_image_io;
+};
+
+/* this is heavily inspired by the bttv driver found in the linux kernel */
+struct v4l2l_format {
+ char *name;
+ int fourcc; /* video4linux 2 */
+ int depth; /* bit/pixel */
+ int flags;
+};
+/* set the v4l2l_format.flags to PLANAR for non-packed formats */
+#define FORMAT_FLAGS_PLANAR 0x01
+#define FORMAT_FLAGS_COMPRESSED 0x02
+
+#ifndef V4L2_PIX_FMT_VP9
+#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
+#endif
+#ifndef V4L2_PIX_FMT_HEVC
+#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C')
+#endif
+
+static const struct v4l2l_format formats[] = {
+#include "v4l2loopback_formats.h"
+};
+
+static const unsigned int FORMATS = ARRAY_SIZE(formats);
+
+
+static char *fourcc2str(unsigned int fourcc, char buf[4])
+{
+ buf[0] = (fourcc >> 0) & 0xFF;
+ buf[1] = (fourcc >> 8) & 0xFF;
+ buf[2] = (fourcc >> 16) & 0xFF;
+ buf[3] = (fourcc >> 24) & 0xFF;
+
+ return buf;
+}
+
+static const struct v4l2l_format *format_by_fourcc(int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < FORMATS; i++) {
+ if (formats[i].fourcc == fourcc)
+ return formats + i;
+ }
+
+ pr_err("unsupported format '%c%c%c%c'\n",
+ (fourcc >> 0) & 0xFF,
+ (fourcc >> 8) & 0xFF,
+ (fourcc >> 16) & 0xFF,
+ (fourcc >> 24) & 0xFF);
+ return NULL;
+}
+
+static void pix_format_set_size(struct v4l2_pix_format *f,
+ const struct v4l2l_format *fmt,
+ unsigned int width, unsigned int height)
+{
+ f->width = width;
+ f->height = height;
+
+ if (fmt->flags & FORMAT_FLAGS_PLANAR) {
+ f->bytesperline = width; /* Y plane */
+ f->sizeimage = (width * height * fmt->depth) >> 3;
+ } else if (fmt->flags & FORMAT_FLAGS_COMPRESSED) {
+ /* doesn't make sense for compressed formats */
+ f->bytesperline = 0;
+ f->sizeimage = (width * height * fmt->depth) >> 3;
+ } else {
+ f->bytesperline = (width * fmt->depth) >> 3;
+ f->sizeimage = height * f->bytesperline;
+ }
+}
+
+static int set_timeperframe(struct v4l2_loopback_device *dev,
+ struct v4l2_fract *tpf)
+{
+ if ((tpf->denominator < 1) || (tpf->numerator < 1))
+ return -EINVAL;
+ dev->capture_param.timeperframe = *tpf;
+ dev->frame_jiffies = max(1UL,
+ msecs_to_jiffies(1000) * tpf->numerator / tpf->denominator);
+ return 0;
+}
+
+static struct v4l2_loopback_device *v4l2loopback_cd2dev(struct device *cd);
+
+/* device attributes */
+/* available via sysfs: /sys/devices/virtual/video4linux/video* */
+
+static ssize_t attr_show_format(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ /* gets the current format as "FOURCC:WxH@f/s",
+ * e.g. "YUYV:320x240@1000/30"
+ */
+ struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd);
+ const struct v4l2_fract *tpf;
+ char buf4cc[5], buf_fps[32];
+
+ if (!dev || !dev->ready_for_capture)
+ return 0;
+ tpf = &dev->capture_param.timeperframe;
+
+ fourcc2str(dev->pix_format.pixelformat, buf4cc);
+ buf4cc[4] = 0;
+ if (tpf->numerator == 1)
+ snprintf(buf_fps, sizeof(buf_fps), "%d", tpf->denominator);
+ else
+ snprintf(buf_fps, sizeof(buf_fps), "%d/%d",
+ tpf->denominator, tpf->numerator);
+ return snprintf(buf, sizeof(buf_fps), "%4s:%dx%d@%s\n",
+ buf4cc, dev->pix_format.width, dev->pix_format.height, buf_fps);
+}
+
+static ssize_t attr_store_format(struct device *cd,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd);
+ int fps_num = 0, fps_den = 1;
+
+ /* only fps changing is supported */
+ if (sscanf(buf, "@%d/%d", &fps_num, &fps_den) > 0) {
+ struct v4l2_fract f = {
+ .numerator = fps_den,
+ .denominator = fps_num
+ };
+ int err = 0;
+
+ err = set_timeperframe(dev, &f);
+ if (err < 0)
+ return err;
+ return len;
+ }
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(format, S_IRUGO | S_IWUSR, attr_show_format,
+ attr_store_format);
+
+static ssize_t attr_show_buffers(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd);
+
+ return snprintf(buf, sizeof(dev->used_buffers), "%d\n",
+ dev->used_buffers);
+}
+
+static DEVICE_ATTR(buffers, S_IRUGO, attr_show_buffers, NULL);
+
+static ssize_t attr_show_maxopeners(struct device *cd,
+ struct device_attribute *attr, char *buf)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd);
+
+ return snprintf(buf, sizeof(dev->max_openers), "%d\n",
+ dev->max_openers);
+}
+
+static ssize_t attr_store_maxopeners(struct device *cd,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct v4l2_loopback_device *dev = NULL;
+ unsigned long curr = 0;
+
+ if (kstrtoul(buf, 0, &curr))
+ return -EINVAL;
+
+ dev = v4l2loopback_cd2dev(cd);
+
+ if (dev->max_openers == curr)
+ return len;
+
+ if (dev->open_count.counter > curr) {
+ /* request to limit to less openers as are
+ * currently attached to us
+ */
+ return -EINVAL;
+ }
+
+ dev->max_openers = (int)curr;
+
+ return len;
+}
+
+
+static DEVICE_ATTR(max_openers, S_IRUGO | S_IWUSR, attr_show_maxopeners,
+ attr_store_maxopeners);
+
+static void v4l2loopback_remove_sysfs(struct video_device *vdev)
+{
+#define V4L2_SYSFS_DESTROY(x) device_remove_file(&vdev->dev, &dev_attr_##x)
+
+ if (vdev) {
+ do {
+ V4L2_SYSFS_DESTROY(format);
+ V4L2_SYSFS_DESTROY(buffers);
+ V4L2_SYSFS_DESTROY(max_openers);
+ /* ... */
+ } while (0);
+ }
+}
+
+static void v4l2loopback_create_sysfs(struct video_device *vdev)
+{
+ int res = 0;
+
+#define V4L2_SYSFS_CREATE(x) \
+ do { \
+ res = device_create_file(&vdev->dev, &dev_attr_##x); \
+ if (res < 0) \
+ break; \
+ } while (0) \
+
+
+ if (!vdev)
+ return;
+ do {
+ V4L2_SYSFS_CREATE(format);
+ V4L2_SYSFS_CREATE(buffers);
+ V4L2_SYSFS_CREATE(max_openers);
+ /* ... */
+ } while (0);
+
+ if (res >= 0)
+ return;
+ dev_err(&vdev->dev, "%s error: %d\n", __func__, res);
+}
+
+/* global module data */
+struct v4l2_loopback_device *devs[MAX_DEVICES];
+
+static struct v4l2_loopback_device *v4l2loopback_cd2dev(struct device *cd)
+{
+ struct video_device *loopdev = to_video_device(cd);
+ struct v4l2loopback_private *ptr =
+ (struct v4l2loopback_private *)video_get_drvdata(loopdev);
+ int nr = ptr->devicenr;
+
+ if (nr < 0 || nr >= devices) {
+ pr_err("v4l2-loopback: illegal device %d\n", nr);
+ return NULL;
+ }
+ return devs[nr];
+}
+
+static struct v4l2_loopback_device *v4l2loopback_getdevice(struct file *f)
+{
+ struct video_device *loopdev = video_devdata(f);
+ struct v4l2loopback_private *ptr =
+ (struct v4l2loopback_private *)video_get_drvdata(loopdev);
+ int nr = ptr->devicenr;
+
+ if (nr < 0 || nr >= devices) {
+ pr_err("v4l2-loopback: illegal device %d\n", nr);
+ return NULL;
+ }
+ return devs[nr];
+}
+
+/* forward declarations */
+static void init_buffers(struct v4l2_loopback_device *dev);
+static int allocate_buffers(struct v4l2_loopback_device *dev);
+static int free_buffers(struct v4l2_loopback_device *dev);
+static void try_free_buffers(struct v4l2_loopback_device *dev);
+static int allocate_timeout_image(struct v4l2_loopback_device *dev);
+static void check_timers(struct v4l2_loopback_device *dev);
+static const struct v4l2_file_operations v4l2_loopback_fops;
+static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops;
+
+/* Queue helpers */
+/* next functions sets buffer flags and adjusts counters accordingly */
+static inline void set_done(struct v4l2l_buffer *buffer)
+{
+ buffer->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+ buffer->buffer.flags |= V4L2_BUF_FLAG_DONE;
+}
+
+static inline void set_queued(struct v4l2l_buffer *buffer)
+{
+ buffer->buffer.flags &= ~V4L2_BUF_FLAG_DONE;
+ buffer->buffer.flags |= V4L2_BUF_FLAG_QUEUED;
+}
+
+static inline void unset_flags(struct v4l2l_buffer *buffer)
+{
+ buffer->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+ buffer->buffer.flags &= ~V4L2_BUF_FLAG_DONE;
+}
+
+static void vidioc_fill_name(char *buf, int len, int nr)
+{
+ if (card_label[nr] != NULL)
+ snprintf(buf, len, card_label[nr]);
+ else
+ snprintf(buf, len, "Dummy video device (0x%04X)", nr);
+}
+
+/* V4L2 ioctl caps and params calls
+ * returns device capabilities
+ * called on VIDIOC_QUERYCAP
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+ int devnr = ((struct v4l2loopback_private *)
+ video_get_drvdata(dev->vdev))->devicenr;
+
+ strlcpy(cap->driver, "v4l2 loopback", sizeof(cap->driver));
+
+ vidioc_fill_name(cap->card, sizeof(cap->card), devnr);
+
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:v4l2loopback-%03d", devnr);
+
+ /* since 3.1.0, the v4l2-core system is supposed to set the version */
+ cap->version = V4L2LOOPBACK_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_DEVICE_CAPS |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+
+#ifdef V4L2_CAP_VIDEO_M2M
+ cap->capabilities |= V4L2_CAP_VIDEO_M2M;
+#endif /* V4L2_CAP_VIDEO_M2M */
+ if (dev->announce_all_caps) {
+ cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_OUTPUT;
+ } else {
+
+ if (dev->ready_for_capture)
+ cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE;
+ if (dev->ready_for_output)
+ cap->capabilities |= V4L2_CAP_VIDEO_OUTPUT;
+ }
+ cap->device_caps = (cap->capabilities & ~V4L2_CAP_DEVICE_CAPS);
+ cap->device_caps = cap->capabilities;
+ cap->capabilities |= V4L2_CAP_DEVICE_CAPS;
+
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *argp)
+{
+ struct v4l2_loopback_device *dev;
+
+ /* LATER: what does the index really mean?
+ * if it's about enumerating formats, we can safely ignore it
+ * (CHECK)
+ */
+
+ /* there can be only one... */
+ if (argp->index)
+ return -EINVAL;
+
+ dev = v4l2loopback_getdevice(file);
+ if (dev->ready_for_capture) {
+ /* format has already been negotiated
+ * cannot change during runtime
+ */
+ argp->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+ argp->discrete.width = dev->pix_format.width;
+ argp->discrete.height = dev->pix_format.height;
+ } else {
+ /* if the format has not been negotiated yet, we accept anything
+ */
+ argp->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+
+ argp->stepwise.min_width = V4L2LOOPBACK_SIZE_MIN_WIDTH;
+ argp->stepwise.min_height = V4L2LOOPBACK_SIZE_MIN_HEIGHT;
+
+ argp->stepwise.max_width = max_width;
+ argp->stepwise.max_height = max_height;
+
+ argp->stepwise.step_width = 1;
+ argp->stepwise.step_height = 1;
+ }
+ return 0;
+}
+
+/* returns frameinterval (fps) for the set resolution
+ * called on VIDIOC_ENUM_FRAMEINTERVALS
+ */
+static int vidioc_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *argp)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+ struct v4l2_loopback_opener *opener = file->private_data;
+
+ if (dev->ready_for_capture) {
+ if (opener->vidioc_enum_frameintervals_calls > 0)
+ return -EINVAL;
+ if (argp->width == dev->pix_format.width &&
+ argp->height == dev->pix_format.height) {
+ argp->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ argp->discrete = dev->capture_param.timeperframe;
+ opener->vidioc_enum_frameintervals_calls++;
+ return 0;
+ }
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ------------------ CAPTURE ----------------------- */
+
+/* returns device formats
+ * called on VIDIOC_ENUM_FMT, with v4l2_buf_type
+ * set to V4L2_BUF_TYPE_VIDEO_CAPTURE
+ */
+static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct v4l2_loopback_device *dev;
+
+ MARK();
+
+ dev = v4l2loopback_getdevice(file);
+
+ if (f->index)
+ return -EINVAL;
+ if (dev->ready_for_capture) {
+ const __u32 format = dev->pix_format.pixelformat;
+
+ snprintf(f->description, sizeof(f->description),
+ "[%c%c%c%c]",
+ (format >> 0) & 0xFF,
+ (format >> 8) & 0xFF,
+ (format >> 16) & 0xFF,
+ (format >> 24) & 0xFF);
+
+ f->pixelformat = dev->pix_format.pixelformat;
+ } else {
+ return -EINVAL;
+ }
+ f->flags = 0;
+ MARK();
+ return 0;
+}
+
+/* returns current video format format fmt
+ * called on VIDIOC_G_FMT, with v4l2_buf_type
+ * set to V4L2_BUF_TYPE_VIDEO_CAPTURE
+ */
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct v4l2_loopback_device *dev;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+
+ if (!dev->ready_for_capture)
+ return -EINVAL;
+
+ fmt->fmt.pix = dev->pix_format;
+ MARK();
+ return 0;
+}
+
+/* checks if it is OK to change to format fmt;
+ * actual check is done by inner_try_fmt_cap
+ * just checking that pixelformat is OK and set other parameters, app should
+ * obey this decision
+ * called on VIDIOC_TRY_FMT, with v4l2_buf_type
+ * set to V4L2_BUF_TYPE_VIDEO_CAPTURE
+ */
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct v4l2_loopback_device *dev;
+ char buf[5];
+
+ dev = v4l2loopback_getdevice(file);
+
+ if (dev->ready_for_capture == 0) {
+ pr_err("setting fmt_cap not possible yet\n");
+ return -EBUSY;
+ }
+
+ if (fmt->fmt.pix.pixelformat != dev->pix_format.pixelformat)
+ return -EINVAL;
+
+ fmt->fmt.pix = dev->pix_format;
+
+ buf[4] = 0;
+ pr_debug("capFOURCC=%s\n", fourcc2str(dev->pix_format.pixelformat,
+ buf));
+ return 0;
+}
+
+/* sets new output format, if possible
+ * actually format is set by input and we even do not check it, just return
+ * current one, but it is possible to set subregions of input TODO(vasaka)
+ * called on VIDIOC_S_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE
+ */
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ return vidioc_try_fmt_cap(file, priv, fmt);
+}
+
+
+/* ------------------ OUTPUT ----------------------- */
+
+/* returns device formats;
+ * LATER: allow all formats
+ * called on VIDIOC_ENUM_FMT, with v4l2_buf_type
+ * set to V4L2_BUF_TYPE_VIDEO_OUTPUT
+ */
+static int vidioc_enum_fmt_out(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct v4l2_loopback_device *dev;
+ const struct v4l2l_format *fmt;
+
+ dev = v4l2loopback_getdevice(file);
+
+ if (dev->ready_for_capture) {
+ const __u32 format = dev->pix_format.pixelformat;
+
+ /* format has been fixed by the writer,
+ * so only one single format is supported
+ */
+ if (f->index)
+ return -EINVAL;
+
+ fmt = format_by_fourcc(format);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ /* f->flags = ??; */
+ snprintf(f->description, sizeof(f->description), "%s",
+ fmt->name);
+
+ f->pixelformat = dev->pix_format.pixelformat;
+ } else {
+ __u32 format;
+
+ /* fill in a dummy format */
+ /* coverity[unsigned_compare] */
+ if (f->index < 0 || f->index >= FORMATS)
+ return -EINVAL;
+
+ fmt = &formats[f->index];
+
+ f->pixelformat = fmt->fourcc;
+ format = f->pixelformat;
+
+ snprintf(f->description, sizeof(f->description), "%s",
+ fmt->name);
+
+ }
+ f->flags = 0;
+
+ return 0;
+}
+
+/* returns current video format format fmt */
+/* NOTE: this is called from the producer
+ * so if format has not been negotiated yet,
+ * it should return ALL of available formats,
+ * called on VIDIOC_G_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT
+ */
+static int vidioc_g_fmt_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct v4l2_loopback_device *dev;
+ struct v4l2_loopback_opener *opener;
+
+ MARK();
+
+ dev = v4l2loopback_getdevice(file);
+ opener = file->private_data;
+
+ /*
+ * LATER: this should return the currently valid format
+ * gstreamer doesn't like it, if this returns -EINVAL, as it
+ * then concludes that there is _no_ valid format
+ * CHECK whether this assumption is wrong,
+ * or whether we have to always provide a valid format
+ */
+
+ fmt->fmt.pix = dev->pix_format;
+ return 0;
+}
+
+/* checks if it is OK to change to format fmt;
+ * if format is negotiated do not change it
+ * called on VIDIOC_TRY_FMT with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT
+ */
+static int vidioc_try_fmt_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct v4l2_loopback_device *dev;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+
+ /* TODO(vasaka) loopback does not care about formats writer want to set,
+ * maybe it is a good idea to restrict format somehow
+ */
+ if (dev->ready_for_capture)
+ fmt->fmt.pix = dev->pix_format;
+ else {
+ __u32 w = fmt->fmt.pix.width;
+ __u32 h = fmt->fmt.pix.height;
+ __u32 pixfmt = fmt->fmt.pix.pixelformat;
+ const struct v4l2l_format *format = format_by_fourcc(pixfmt);
+
+ if (w > max_width)
+ w = max_width;
+ if (h > max_height)
+ h = max_height;
+
+ pr_debug("trying image %dx%d\n", w, h);
+
+ if (w < 1)
+ w = V4L2LOOPBACK_SIZE_DEFAULT_WIDTH;
+
+ if (h < 1)
+ h = V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT;
+
+ if (format == NULL)
+ format = &formats[0];
+
+ pix_format_set_size(&fmt->fmt.pix, format, w, h);
+
+ fmt->fmt.pix.pixelformat = format->fourcc;
+ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+
+ if (fmt->fmt.pix.field == V4L2_FIELD_ANY)
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+
+ /* FIXXME: try_fmt should never modify the device-state */
+ dev->pix_format = fmt->fmt.pix;
+ }
+ return 0;
+}
+
+/* sets new output format, if possible;
+ * allocate data here because we do not know if it will be streaming or
+ * read/write IO
+ * called on VIDIOC_S_FMT with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT
+ */
+static int vidioc_s_fmt_out(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct v4l2_loopback_device *dev;
+ char buf[5];
+ int ret;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+ ret = vidioc_try_fmt_out(file, priv, fmt);
+
+ pr_debug("s_fmt_out(%d) %d...%d\n", ret, dev->ready_for_capture,
+ dev->pix_format.sizeimage);
+
+ buf[4] = 0;
+ pr_debug("outFOURCC=%s\n", fourcc2str(dev->pix_format.pixelformat,
+ buf));
+
+ if (ret < 0)
+ return ret;
+
+ if (!dev->ready_for_capture) {
+ dev->buffer_size = PAGE_ALIGN(dev->pix_format.sizeimage);
+ fmt->fmt.pix.sizeimage = dev->buffer_size;
+ allocate_buffers(dev);
+ }
+ return ret;
+}
+
+/*#define V4L2L_OVERLAY*/
+#ifdef V4L2L_OVERLAY
+/* ------------------ OVERLAY ----------------------- */
+/* currently unsupported */
+/* GSTreamer's v4l2sink is buggy, as it requires the overlay to work
+ * while it should only require it, if overlay is requested
+ * once the gstreamer element is fixed, remove the overlay dummies
+ */
+#warning OVERLAY dummies
+static int vidioc_g_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ return 0;
+}
+
+static int vidioc_s_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ return 0;
+}
+#endif /* V4L2L_OVERLAY */
+
+
+/* ------------------ PARAMs ----------------------- */
+
+/* get some data flow parameters, only capability, fps and readbuffers has
+ * effect on this driver
+ * called on VIDIOC_G_PARM
+ */
+static int vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ /* do not care about type of opener, hope this enums would always be
+ * compatible
+ */
+ struct v4l2_loopback_device *dev;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+ parm->parm.capture = dev->capture_param;
+ return 0;
+}
+
+/* get some data flow parameters, only capability, fps and readbuffers has
+ * effect on this driver
+ * called on VIDIOC_S_PARM
+ */
+static int vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_loopback_device *dev;
+ int err = 0;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+ pr_debug("vidioc_s_parm called frate=%d/%d\n",
+ parm->parm.capture.timeperframe.numerator,
+ parm->parm.capture.timeperframe.denominator);
+
+ switch (parm->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ err = set_timeperframe(dev, &parm->parm.capture.timeperframe);
+ if (err < 0)
+ return err;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ err = set_timeperframe(dev, &parm->parm.capture.timeperframe);
+ if (err < 0)
+ return err;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ parm->parm.capture = dev->capture_param;
+ return 0;
+}
+
+#ifdef V4L2LOOPBACK_WITH_STD
+/* sets a tv standard, actually we do not need to handle this any special way
+ * added to support effecttv
+ * called on VIDIOC_S_STD
+ */
+static int vidioc_s_std(struct file *file, void *private_data,
+ v4l2_std_id *_std)
+{
+ v4l2_std_id req_std = 0, supported_std = 0;
+ const v4l2_std_id all_std = V4L2_STD_ALL, no_std = 0;
+
+ if (_std) {
+ req_std = *_std;
+ *_std = all_std;
+ }
+
+ /* we support everything in V4L2_STD_ALL, but not more... */
+ supported_std = (all_std & req_std);
+ if (no_std == supported_std)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+/* gets a fake video standard
+ * called on VIDIOC_G_STD
+ */
+static int vidioc_g_std(struct file *file, void *private_data,
+ v4l2_std_id *norm)
+{
+ if (norm)
+ *norm = V4L2_STD_ALL;
+ return 0;
+}
+/* gets a fake video standard
+ * called on VIDIOC_QUERYSTD
+ */
+static int vidioc_querystd(struct file *file, void *private_data,
+ v4l2_std_id *norm)
+{
+ if (norm)
+ *norm = V4L2_STD_ALL;
+ return 0;
+}
+#endif /* V4L2LOOPBACK_WITH_STD */
+
+/* get ctrls info
+ * called on VIDIOC_QUERYCTRL
+ */
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *q)
+{
+ const struct v4l2_ctrl_config *cnf = 0;
+
+ switch (q->id) {
+ case CID_KEEP_FORMAT:
+ cnf = &v4l2loopback_ctrl_keepformat;
+ break;
+ case CID_SUSTAIN_FRAMERATE:
+ cnf = &v4l2loopback_ctrl_sustainframerate;
+ break;
+ case CID_TIMEOUT:
+ cnf = &v4l2loopback_ctrl_timeout;
+ break;
+ case CID_TIMEOUT_IMAGE_IO:
+ cnf = &v4l2loopback_ctrl_timeoutimageio;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!cnf)
+ WARN_ON(1);
+
+ strlcpy(q->name, cnf->name, sizeof(q->name));
+ q->default_value = cnf->def;
+ q->type = cnf->type;
+ q->minimum = cnf->min;
+ q->maximum = cnf->max;
+ q->step = cnf->step;
+
+ memset(q->reserved, 0, sizeof(q->reserved));
+ return 0;
+}
+
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+
+ switch (c->id) {
+ case CID_KEEP_FORMAT:
+ c->value = dev->keep_format;
+ break;
+ case CID_SUSTAIN_FRAMERATE:
+ c->value = dev->sustain_framerate;
+ break;
+ case CID_TIMEOUT:
+ c->value = jiffies_to_msecs(dev->timeout_jiffies);
+ break;
+ case CID_TIMEOUT_IMAGE_IO:
+ c->value = dev->timeout_image_io;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int v4l2loopback_set_ctrl(struct v4l2_loopback_device *dev,
+ u32 id,
+ s64 val)
+{
+ switch (id) {
+ case CID_KEEP_FORMAT:
+ if (val < 0 || val > 1)
+ return -EINVAL;
+ dev->keep_format = val;
+ try_free_buffers(dev);
+ break;
+ case CID_SUSTAIN_FRAMERATE:
+ if (val < 0 || val > 1)
+ return -EINVAL;
+ spin_lock_bh(&dev->lock);
+ dev->sustain_framerate = val;
+ check_timers(dev);
+ spin_unlock_bh(&dev->lock);
+ break;
+ case CID_TIMEOUT:
+ if (val < 0 || val > MAX_TIMEOUT)
+ return -EINVAL;
+ spin_lock_bh(&dev->lock);
+ dev->timeout_jiffies = msecs_to_jiffies(val);
+ check_timers(dev);
+ spin_unlock_bh(&dev->lock);
+ allocate_timeout_image(dev);
+ break;
+ case CID_TIMEOUT_IMAGE_IO:
+ if (val < 0 || val > 1)
+ return -EINVAL;
+ dev->timeout_image_io = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int v4l2loopback_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_loopback_device *dev = container_of(ctrl->handler,
+ struct v4l2_loopback_device, ctrl_handler);
+
+ return v4l2loopback_set_ctrl(dev, ctrl->id, ctrl->val);
+}
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+
+ return v4l2loopback_set_ctrl(dev, c->id, c->value);
+}
+
+/* returns set of device outputs, in our case there is only one
+ * called on VIDIOC_ENUMOUTPUT
+ */
+static int vidioc_enum_output(struct file *file, void *fh,
+ struct v4l2_output *outp)
+{
+ __u32 index = outp->index;
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+
+ MARK();
+ if (!dev->announce_all_caps && !dev->ready_for_output)
+ return -ENOTTY;
+
+ if (index != 0)
+ return -EINVAL;
+
+ /* clear all data (including the reserved fields) */
+ memset(outp, 0, sizeof(*outp));
+
+ outp->index = index;
+ strlcpy(outp->name, "loopback in", sizeof(outp->name));
+ outp->type = V4L2_OUTPUT_TYPE_ANALOG;
+ outp->audioset = 0;
+ outp->modulator = 0;
+#ifdef V4L2LOOPBACK_WITH_STD
+ outp->std = V4L2_STD_ALL;
+# ifdef V4L2_OUT_CAP_STD
+ outp->capabilities |= V4L2_OUT_CAP_STD;
+# endif /* V4L2_OUT_CAP_STD */
+#endif /* V4L2LOOPBACK_WITH_STD */
+
+ return 0;
+}
+
+/* which output is currently active,
+ * called on VIDIOC_G_OUTPUT
+ */
+static int vidioc_g_output(struct file *file, void *fh, unsigned int *i)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+
+ if (!dev->announce_all_caps && !dev->ready_for_output)
+ return -ENOTTY;
+ if (i)
+ *i = 0;
+ return 0;
+}
+
+/* set output, can make sense if we have more than one video src,
+ * called on VIDIOC_S_OUTPUT
+ */
+static int vidioc_s_output(struct file *file, void *fh, unsigned int i)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+
+ if (!dev->announce_all_caps && !dev->ready_for_output)
+ return -ENOTTY;
+
+ if (i)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+/* returns set of device inputs, in our case there is only one,
+ * but later I may add more
+ * called on VIDIOC_ENUMINPUT
+ */
+static int vidioc_enum_input(struct file *file, void *fh,
+ struct v4l2_input *inp)
+{
+ __u32 index = inp->index;
+
+ MARK();
+ if (index != 0)
+ return -EINVAL;
+
+ /* clear all data (including the reserved fields) */
+ memset(inp, 0, sizeof(*inp));
+
+ inp->index = index;
+ strlcpy(inp->name, "loopback", sizeof(inp->name));
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->audioset = 0;
+ inp->tuner = 0;
+ inp->status = 0;
+
+#ifdef V4L2LOOPBACK_WITH_STD
+ inp->std = V4L2_STD_ALL;
+# ifdef V4L2_IN_CAP_STD
+ inp->capabilities |= V4L2_IN_CAP_STD;
+# endif
+#endif /* V4L2LOOPBACK_WITH_STD */
+
+ return 0;
+}
+
+/* which input is currently active,
+ * called on VIDIOC_G_INPUT
+ */
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+
+ if (!dev->announce_all_caps && !dev->ready_for_capture)
+ return -ENOTTY;
+ if (i)
+ *i = 0;
+ return 0;
+}
+
+/* set input, can make sense if we have more than one video src,
+ * called on VIDIOC_S_INPUT
+ */
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+
+ if (!dev->announce_all_caps && !dev->ready_for_capture)
+ return -ENOTTY;
+ if (i == 0)
+ return 0;
+ return -EINVAL;
+}
+
+/* --------------- V4L2 ioctl buffer related calls ----------------- */
+
+/* negotiate buffer type
+ * only mmap streaming supported
+ * called on VIDIOC_REQBUFS
+ */
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct v4l2_loopback_device *dev;
+ struct v4l2_loopback_opener *opener;
+ int i;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+ opener = file->private_data;
+
+ if (opener->timeout_image_io) {
+ if (b->memory != V4L2_MEMORY_MMAP && b->memory !=
+ V4L2_MEMORY_USERPTR)
+ return -EINVAL;
+ b->count = 1;
+ return 0;
+ }
+
+ init_buffers(dev);
+ switch (b->memory) {
+ case V4L2_MEMORY_USERPTR:
+ case V4L2_MEMORY_MMAP:
+ /* do nothing here, buffers are always allocated */
+ if (b->count < 1 || dev->buffers_number < 1)
+ return 0;
+
+ if (b->count > dev->buffers_number)
+ b->count = dev->buffers_number;
+
+ /* make sure that outbufs_list contains buffers
+ * from 0 to used_buffers-1 actually, it will have been
+ * already populated via v4l2_loopback_init()
+ * at this point
+ */
+ if (list_empty(&dev->outbufs_list)) {
+ for (i = 0; i < dev->used_buffers; ++i)
+ list_add_tail(&dev->buffers[i].list_head,
+ &dev->outbufs_list);
+ }
+
+ /* also, if dev->used_buffers is going to be decreased,
+ * we should remove out-of-range buffers from outbufs_list,
+ * and fix bufpos2index mapping
+ */
+ if (b->count < dev->used_buffers) {
+ struct v4l2l_buffer *pos, *n;
+
+ list_for_each_entry_safe(pos, n,
+ &dev->outbufs_list, list_head) {
+ if (pos->buffer.index >= b->count)
+ list_del(&pos->list_head);
+ }
+
+ /* after we update dev->used_buffers, buffers
+ * in outbufs_list will correspond to
+ * dev->write_position + [0;b->count-1] range
+ */
+ i = dev->write_position;
+ list_for_each_entry(pos,
+ &dev->outbufs_list, list_head) {
+ dev->bufpos2index[i % b->count] =
+ pos->buffer.index;
+ ++i;
+ }
+ }
+
+ opener->buffers_number = b->count;
+ if (opener->buffers_number < dev->used_buffers)
+ dev->used_buffers = opener->buffers_number;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* returns buffer asked for;
+ * give app as many buffers as it wants, if it less than MAX,
+ * but map them in our inner buffers
+ * called on VIDIOC_QUERYBUF
+ */
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ enum v4l2_buf_type type;
+ int index;
+ struct v4l2_loopback_device *dev;
+ struct v4l2_loopback_opener *opener;
+
+ MARK();
+
+ type = b->type;
+ index = b->index;
+ dev = v4l2loopback_getdevice(file);
+ opener = file->private_data;
+
+ if ((b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (b->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) {
+ return -EINVAL;
+ }
+ if (b->index > max_buffers)
+ return -EINVAL;
+
+ if (opener->timeout_image_io)
+ *b = dev->timeout_image_buffer.buffer;
+ else
+ *b = dev->buffers[b->index % dev->used_buffers].buffer;
+
+ b->type = type;
+ b->index = index;
+ pr_debug("buffer type: %d (of %d with size=%ld)\n",
+ b->memory, dev->buffers_number, dev->buffer_size);
+
+ /* Hopefully fix 'DQBUF return bad index if queue bigger
+ * then 2 for capture'
+ * https://github.com/umlaeute/v4l2loopback/issues/60
+ */
+ b->flags &= ~V4L2_BUF_FLAG_DONE;
+ b->flags |= V4L2_BUF_FLAG_QUEUED;
+
+ return 0;
+}
+
+static void buffer_written(struct v4l2_loopback_device *dev,
+ struct v4l2l_buffer *buf)
+{
+ del_timer_sync(&dev->sustain_timer);
+ del_timer_sync(&dev->timeout_timer);
+ spin_lock_bh(&dev->lock);
+
+ dev->bufpos2index[dev->write_position %
+ dev->used_buffers] = buf->buffer.index;
+ list_move_tail(&buf->list_head, &dev->outbufs_list);
+ ++dev->write_position;
+ dev->reread_count = 0;
+
+ check_timers(dev);
+ spin_unlock_bh(&dev->lock);
+}
+
+/* put buffer to queue
+ * called on VIDIOC_QBUF
+ */
+static int vidioc_qbuf(struct file *file,
+ void *private_data, struct v4l2_buffer *buf)
+{
+ struct v4l2_loopback_device *dev;
+ struct v4l2_loopback_opener *opener;
+ struct v4l2l_buffer *b;
+ int index;
+
+ dev = v4l2loopback_getdevice(file);
+ opener = file->private_data;
+
+ if (buf->index > max_buffers)
+ return -EINVAL;
+ if (opener->timeout_image_io)
+ return 0;
+
+ index = buf->index % dev->used_buffers;
+ b = &dev->buffers[index];
+
+ switch (buf->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pr_debug("capture QBUF index: %d\n", index);
+ set_queued(b);
+ return 0;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ pr_debug("output QBUF pos: %d index: %d\n",
+ dev->write_position, index);
+ if (buf->timestamp.tv_sec == 0 && buf->timestamp.tv_usec == 0)
+ do_gettimeofday(&b->buffer.timestamp);
+ else
+ b->buffer.timestamp = buf->timestamp;
+ b->buffer.bytesused = buf->bytesused;
+ set_done(b);
+ buffer_written(dev, b);
+
+ /* Hopefully fix 'DQBUF return bad index if queue
+ * bigger then 2 for capture'
+ * https://github.com/umlaeute/v4l2loopback/issues/60
+ */
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+
+ wake_up_all(&dev->read_event);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int can_read(struct v4l2_loopback_device *dev,
+ struct v4l2_loopback_opener *opener)
+{
+ int ret;
+
+ spin_lock_bh(&dev->lock);
+ check_timers(dev);
+ ret = dev->write_position > opener->read_position
+ || dev->reread_count > opener->reread_count
+ || dev->timeout_happened;
+ spin_unlock_bh(&dev->lock);
+ return ret;
+}
+
+
+static int can_read_start_stop(struct v4l2_loopback_device *dev,
+ struct v4l2_loopback_opener *opener)
+{
+
+ int ret;
+
+ spin_lock_bh(&dev->lock);
+ check_timers(dev);
+ ret = dev->streamon_complete > 0 || dev->close_complete > 0;
+ spin_unlock_bh(&dev->lock);
+ pr_debug("Entering in wait for poll response from v4l2-loopback\n");
+ return ret;
+}
+
+static int get_capture_buffer(struct file *file)
+{
+ struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file);
+ struct v4l2_loopback_opener *opener = file->private_data;
+ int pos, ret;
+ int timeout_happened;
+
+ if ((file->f_flags & O_NONBLOCK) &&
+ (dev->write_position <= opener->read_position &&
+ dev->reread_count <= opener->reread_count
+ && !dev->timeout_happened))
+ return -EAGAIN;
+ wait_event_interruptible(dev->read_event, can_read(dev, opener));
+
+ spin_lock_bh(&dev->lock);
+ if (dev->write_position == opener->read_position) {
+ if (dev->reread_count > opener->reread_count + 2)
+ opener->reread_count = dev->reread_count - 1;
+ ++opener->reread_count;
+ pos = (opener->read_position +
+ dev->used_buffers - 1) % dev->used_buffers;
+ } else {
+ opener->reread_count = 0;
+ if (dev->write_position > opener->read_position + 2)
+ opener->read_position = dev->write_position - 1;
+ pos = opener->read_position % dev->used_buffers;
+ ++opener->read_position;
+ }
+ timeout_happened = dev->timeout_happened;
+ dev->timeout_happened = 0;
+ spin_unlock_bh(&dev->lock);
+
+ ret = dev->bufpos2index[pos];
+ if (timeout_happened) {
+ /* although allocated on-demand, timeout_image is freed only
+ * in free_buffers(), so we don't need to worry about it being
+ * deallocated suddenly
+ */
+ memcpy(dev->image + dev->buffers[ret].buffer.m.offset,
+ dev->timeout_image, dev->buffer_size);
+ }
+ return ret;
+}
+
+/* put buffer to dequeue
+ * called on VIDIOC_DQBUF
+ */
+static int vidioc_dqbuf(struct file *file,
+ void *private_data, struct v4l2_buffer *buf)
+{
+ struct v4l2_loopback_device *dev;
+ struct v4l2_loopback_opener *opener;
+ int index;
+ struct v4l2l_buffer *b;
+
+ dev = v4l2loopback_getdevice(file);
+ opener = file->private_data;
+ if (opener->timeout_image_io) {
+ *buf = dev->timeout_image_buffer.buffer;
+ return 0;
+ }
+
+ switch (buf->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ index = get_capture_buffer(file);
+ if (index < 0)
+ return index;
+ pr_debug("capture DQBUF pos: %d index: %d\n",
+ opener->read_position - 1, index);
+ if (!(dev->buffers[index].buffer.flags&V4L2_BUF_FLAG_MAPPED))
+ pr_debug("trying to ret not mapped buf[%d]\n", index);
+ unset_flags(&dev->buffers[index]);
+ *buf = dev->buffers[index].buffer;
+ return 0;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ b = list_entry(dev->outbufs_list.prev,
+ struct v4l2l_buffer, list_head);
+ list_move_tail(&b->list_head, &dev->outbufs_list);
+ pr_debug("output DQBUF index: %d\n", b->buffer.index);
+ unset_flags(b);
+ *buf = b->buffer;
+ buf->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* ------------- STREAMING ------------------- */
+
+/* start streaming
+ * called on VIDIOC_STREAMON
+ */
+static int vidioc_streamon(struct file *file,
+ void *private_data, enum v4l2_buf_type type)
+{
+ struct v4l2_loopback_device *dev;
+ struct v4l2_loopback_opener *opener;
+ int ret;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+ opener = file->private_data;
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ opener->type = WRITER;
+ dev->ready_for_output = 0;
+ if (!dev->ready_for_capture) {
+ ret = allocate_buffers(dev);
+ if (ret < 0)
+ return ret;
+ dev->ready_for_capture = 1;
+ }
+ return 0;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ opener->type = READER;
+ if (!dev->ready_for_capture)
+ return -EIO;
+ spin_lock_bh(&dev->lock);
+ if (dev->streamon_check == 0) {
+ dev->streamon_complete = 1;
+ dev->close_complete = 0;
+ dev->stream_close_check = 0;
+ wake_up_all(&dev->write_event);
+ }
+ spin_unlock_bh(&dev->lock);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* stop streaming
+ * called on VIDIOC_STREAMOFF
+ */
+static int vidioc_streamoff(struct file *file,
+ void *private_data, enum v4l2_buf_type type)
+{
+ struct v4l2_loopback_device *dev;
+
+ dev = v4l2loopback_getdevice(file);
+
+ MARK();
+ spin_lock_bh(&dev->lock);
+ if (dev->stream_close_check == 0) {
+
+ dev->close_complete = 1;
+ dev->streamon_check = 0;
+ wake_up_all(&dev->write_event);
+ }
+ spin_unlock_bh(&dev->lock);
+
+ pr_debug("Entering in v4l2 loopback streamoff api\n");
+ pr_debug("%d\n", type);
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *fh, struct video_mbuf *p)
+{
+ struct v4l2_loopback_device *dev;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+ p->frames = dev->buffers_number;
+ p->offsets[0] = 0;
+ p->offsets[1] = 0;
+ p->size = dev->buffer_size;
+ return 0;
+}
+#endif
+
+/* file operations */
+static void vm_open(struct vm_area_struct *vma)
+{
+ struct v4l2l_buffer *buf;
+
+ MARK();
+ buf = vma->vm_private_data;
+ buf->use_count++;
+}
+
+static void vm_close(struct vm_area_struct *vma)
+{
+ struct v4l2l_buffer *buf;
+
+ MARK();
+ buf = vma->vm_private_data;
+ buf->use_count--;
+}
+
+static struct vm_operations_struct vm_ops = {
+ .open = vm_open,
+ .close = vm_close,
+};
+
+static int v4l2_loopback_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int i;
+ unsigned long addr;
+ unsigned long start;
+ unsigned long size;
+ struct v4l2_loopback_device *dev;
+ struct v4l2_loopback_opener *opener;
+ struct v4l2l_buffer *buffer = NULL;
+
+ MARK();
+ start = (unsigned long) vma->vm_start;
+ size = (unsigned long) (vma->vm_end - vma->vm_start);
+
+ dev = v4l2loopback_getdevice(file);
+ opener = file->private_data;
+
+ if (size > dev->buffer_size) {
+ pr_err("userspace tries to mmap too much, fail\n");
+ return -EINVAL;
+ }
+ if (opener->timeout_image_io) {
+ /* we are going to map the timeout_image_buffer */
+ if ((vma->vm_pgoff << PAGE_SHIFT)
+ != dev->buffer_size * MAX_BUFFERS) {
+ pr_err("invalid mmap offset for timeout_image_io mode\n");
+ return -EINVAL;
+ }
+ } else if ((vma->vm_pgoff << PAGE_SHIFT) >
+ dev->buffer_size * (dev->buffers_number - 1)) {
+ pr_err("userspace tries to mmap too far, fail\n");
+ return -EINVAL;
+ }
+
+ /* FIXXXXXME: allocation should not happen here! */
+ if (dev->image == NULL)
+ if (allocate_buffers(dev) < 0)
+ return -EINVAL;
+
+ if (opener->timeout_image_io) {
+ buffer = &dev->timeout_image_buffer;
+ addr = (unsigned long)dev->timeout_image;
+ } else {
+ for (i = 0; i < dev->buffers_number; ++i) {
+ buffer = &dev->buffers[i];
+ if ((buffer->buffer.m.offset >> PAGE_SHIFT)
+ == vma->vm_pgoff)
+ break;
+ }
+
+ if (buffer == NULL)
+ return -EINVAL;
+
+ addr = (unsigned long) dev->image +
+ (vma->vm_pgoff << PAGE_SHIFT);
+ }
+
+ while (size > 0) {
+ struct page *page;
+
+ page = (void *)vmalloc_to_page((void *)addr);
+
+ if (vm_insert_page(vma, start, page) < 0)
+ return -EAGAIN;
+
+ start += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &vm_ops;
+ vma->vm_private_data = buffer;
+ buffer->buffer.flags |= V4L2_BUF_FLAG_MAPPED;
+
+ vm_open(vma);
+
+ MARK();
+ return 0;
+}
+
+static unsigned int v4l2_loopback_poll(struct file *file
+ , struct poll_table_struct *pts)
+{
+ struct v4l2_loopback_opener *opener;
+ struct v4l2_loopback_device *dev;
+ int ret_mask = 0;
+
+ MARK();
+ opener = file->private_data;
+ dev = v4l2loopback_getdevice(file);
+
+ wait_event_interruptible(dev->write_event,
+ can_read_start_stop(dev, opener));
+ spin_lock_bh(&dev->lock);
+ if (dev->streamon_complete == 1 && dev->streamon_check == 0) {
+
+ ret_mask = POLLIN | POLLRDNORM;
+ dev->streamon_complete = 0;
+ dev->streamon_check = 1;
+ pr_debug("poll response from v4l2-loopback for streamon == %d\n"
+ , ret_mask);
+
+ } else if (dev->close_complete == 1 && dev->stream_close_check == 0) {
+
+ ret_mask = POLL_CLOSE_EVENT;
+ dev->close_complete = 0;
+ dev->stream_close_check = 1;
+ pr_debug("poll response from v4l2-loopback for close %d\n"
+ , ret_mask);
+
+ } else {
+
+ pr_debug("poll response from v4l2-loopback in case of error\n");
+ ret_mask = -POLLERR;
+ }
+ spin_unlock_bh(&dev->lock);
+ MARK();
+
+ return ret_mask;
+}
+
+/* do not want to limit device opens, it can be as many readers as user want,
+ * writers are limited by means of setting writer field
+ */
+static int v4l2_loopback_open(struct file *file)
+{
+ struct v4l2_loopback_device *dev;
+ struct v4l2_loopback_opener *opener;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+
+ if (dev->open_count.counter >= dev->max_openers)
+ return -EBUSY;
+ /* kfree on close */
+ opener = kzalloc(sizeof(*opener), GFP_KERNEL);
+ if (opener == NULL)
+ return -ENOMEM;
+ file->private_data = opener;
+ atomic_inc(&dev->open_count);
+
+ opener->timeout_image_io = dev->timeout_image_io;
+ dev->timeout_image_io = 0;
+
+ if (opener->timeout_image_io) {
+ int r = allocate_timeout_image(dev);
+
+ if (r < 0) {
+ pr_err("timeout image allocation failed\n");
+ return r;
+ }
+ }
+ pr_debug("opened dev:%p with image:%p\n", dev, dev ? dev->image : NULL);
+ MARK();
+ return 0;
+}
+
+static int v4l2_loopback_close(struct file *file)
+{
+ struct v4l2_loopback_opener *opener;
+ struct v4l2_loopback_device *dev;
+ int iswriter = 0;
+
+ MARK();
+ opener = file->private_data;
+ dev = v4l2loopback_getdevice(file);
+
+ if (opener->type == WRITER)
+ iswriter = 1;
+
+ atomic_dec(&dev->open_count);
+ if (dev->open_count.counter == 0) {
+ del_timer_sync(&dev->sustain_timer);
+ del_timer_sync(&dev->timeout_timer);
+ }
+ try_free_buffers(dev);
+ kfree(opener);
+ if (iswriter)
+ dev->ready_for_output = 1;
+
+ MARK();
+
+ return 0;
+}
+
+static ssize_t v4l2_loopback_read(struct file *file,
+ char __user *buf, size_t count, loff_t *ppos)
+{
+ int read_index;
+ struct v4l2_loopback_opener *opener;
+ struct v4l2_loopback_device *dev;
+ struct v4l2_buffer *b;
+
+ MARK();
+ opener = file->private_data;
+ dev = v4l2loopback_getdevice(file);
+
+ read_index = get_capture_buffer(file);
+ if (read_index < 0)
+ return read_index;
+ if (count > dev->buffer_size) {
+ pr_err("v4l2-loopback_read(): Size is not equals to buf size\n");
+ count = dev->buffer_size;
+ }
+ b = &dev->buffers[read_index].buffer;
+ if (count > b->bytesused)
+ count = b->bytesused;
+ if (copy_to_user((void *)buf,
+ (void *)(dev->image + b->m.offset), count)) {
+ pr_debug("v4l2-loopback: failed copy_to_user() in read buf\n");
+ return -EFAULT;
+ }
+ pr_debug("leave v4l2_loopback_read()\n");
+ return count;
+}
+
+static ssize_t v4l2_loopback_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct v4l2_loopback_device *dev;
+ int write_index;
+ struct v4l2_buffer *b;
+ int ret;
+
+ MARK();
+ dev = v4l2loopback_getdevice(file);
+
+ /* there's at least one writer,
+ * so don'stop announcing output capabilities
+ */
+ dev->ready_for_output = 0;
+
+ if (!dev->ready_for_capture) {
+ ret = allocate_buffers(dev);
+ if (ret < 0)
+ return ret;
+ dev->ready_for_capture = 1;
+ }
+ pr_debug("v4l2_loopback_write() trying to write %zu bytes\n", count);
+ if (count > dev->buffer_size) {
+ pr_err("v4l2-loopback_write(): Size is not equals to buf size\n");
+ count = dev->buffer_size;
+ }
+
+ write_index = dev->write_position % dev->used_buffers;
+ b = &dev->buffers[write_index].buffer;
+
+ if (copy_from_user((void *)(dev->image + b->m.offset),
+ (void *)buf, count)) {
+ pr_err("v4l2-loopback: failed copy_from_user() in write buf, could not write %zu\n",
+ count);
+ return -EFAULT;
+ }
+ do_gettimeofday(&b->timestamp);
+ b->bytesused = count;
+ b->sequence = dev->write_position;
+ buffer_written(dev, &dev->buffers[write_index]);
+ wake_up_all(&dev->read_event);
+ pr_debug("leave v4l2_loopback_write()\n");
+ return count;
+}
+
+/* init functions */
+/* frees buffers, if already allocated */
+static int free_buffers(struct v4l2_loopback_device *dev)
+{
+ MARK();
+ pr_debug("freeing image@%p for dev:%p\n", dev ? dev->image : NULL, dev);
+ if (dev->image) {
+ vfree(dev->image);
+ dev->image = NULL;
+ }
+ if (dev->timeout_image) {
+ vfree(dev->timeout_image);
+ dev->timeout_image = NULL;
+ }
+ dev->imagesize = 0;
+
+ return 0;
+}
+/* frees buffers, if they are no longer needed */
+static void try_free_buffers(struct v4l2_loopback_device *dev)
+{
+ MARK();
+ if (dev->open_count.counter && !dev->keep_format == 0) {
+ free_buffers(dev);
+ dev->ready_for_capture = 0;
+ dev->buffer_size = 0;
+ dev->write_position = 0;
+ }
+}
+/* allocates buffers, if buffer_size is set */
+static int allocate_buffers(struct v4l2_loopback_device *dev)
+{
+ MARK();
+ /* vfree on close file operation in case no open handles left */
+ if (dev->buffer_size == 0)
+ return -EINVAL;
+
+ if (dev->image) {
+ pr_debug("allocating buffers again: %ld %ld\n",
+ dev->buffer_size * dev->buffers_number, dev->imagesize);
+ /* FIXME: prevent double allocation more intelligently! */
+ if (dev->buffer_size * dev->buffers_number == dev->imagesize)
+ return 0;
+
+ /* if there is only one writer, no problem should occur */
+ if (dev->open_count.counter == 1)
+ free_buffers(dev);
+ else
+ return -EINVAL;
+ }
+
+ dev->imagesize = dev->buffer_size * dev->buffers_number;
+
+ pr_debug("allocating %ld = %ldx%d\n",
+ dev->imagesize, dev->buffer_size, dev->buffers_number);
+
+ dev->image = vmalloc(dev->imagesize);
+ if (dev->timeout_jiffies > 0)
+ allocate_timeout_image(dev);
+
+ if (dev->image == NULL)
+ return -ENOMEM;
+ pr_debug("vmallocated %ld bytes\n", dev->imagesize);
+ MARK();
+ init_buffers(dev);
+ return 0;
+}
+
+/* init inner buffers, they are capture mode and flags are set as
+ * for capture mod buffers
+ */
+static void init_buffers(struct v4l2_loopback_device *dev)
+{
+ int i;
+ int buffer_size;
+ int bytesused;
+
+ MARK();
+ buffer_size = dev->buffer_size;
+ bytesused = dev->pix_format.sizeimage;
+
+ for (i = 0; i < dev->buffers_number; ++i) {
+ struct v4l2_buffer *b = &dev->buffers[i].buffer;
+
+ b->index = i;
+ b->bytesused = bytesused;
+ b->length = buffer_size;
+ b->field = V4L2_FIELD_NONE;
+ b->flags = 0;
+ b->m.offset = i * buffer_size;
+ b->memory = V4L2_MEMORY_MMAP;
+ b->sequence = 0;
+ b->timestamp.tv_sec = 0;
+ b->timestamp.tv_usec = 0;
+ b->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ do_gettimeofday(&b->timestamp);
+ }
+ dev->timeout_image_buffer = dev->buffers[0];
+ dev->timeout_image_buffer.buffer.m.offset = MAX_BUFFERS * buffer_size;
+ MARK();
+}
+
+static int allocate_timeout_image(struct v4l2_loopback_device *dev)
+{
+ MARK();
+ if (dev->buffer_size <= 0)
+ return -EINVAL;
+
+ if (dev->timeout_image == NULL) {
+ dev->timeout_image = v4l2l_vzalloc(dev->buffer_size);
+ if (dev->timeout_image == NULL)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/* fills and register video device */
+static void init_vdev(struct video_device *vdev, int nr)
+{
+ MARK();
+ vidioc_fill_name(vdev->name, sizeof(vdev->name), nr);
+
+#ifdef V4L2LOOPBACK_WITH_STD
+ vdev->tvnorms = V4L2_STD_ALL;
+#endif /* V4L2LOOPBACK_WITH_STD */
+
+ vdev->vfl_type = VFL_TYPE_GRABBER;
+ vdev->fops = &v4l2_loopback_fops;
+ vdev->ioctl_ops = &v4l2_loopback_ioctl_ops;
+ vdev->release = &video_device_release;
+ vdev->minor = -1;
+ if (debug > 1)
+ vdev->dev_debug =
+ V4L2_DEV_DEBUG_IOCTL | V4L2_DEV_DEBUG_IOCTL_ARG;
+
+ /* since kernel-3.7, there is a new field 'vfl_dir' that has to be
+ * set to VFL_DIR_M2M for bidrectional devices
+ */
+ vdev->vfl_dir = VFL_DIR_M2M;
+
+ MARK();
+}
+
+/* init default capture parameters, only fps may be changed in future */
+static void init_capture_param(struct v4l2_captureparm *capture_param)
+{
+ MARK();
+ capture_param->capability = 0;
+ capture_param->capturemode = 0;
+ capture_param->extendedmode = 0;
+ capture_param->readbuffers = max_buffers;
+ capture_param->timeperframe.numerator = 1;
+ capture_param->timeperframe.denominator = 30;
+}
+
+static void check_timers(struct v4l2_loopback_device *dev)
+{
+ if (!dev->ready_for_capture)
+ return;
+
+ if (dev->timeout_jiffies > 0 && !timer_pending(&dev->timeout_timer))
+ mod_timer(&dev->timeout_timer, jiffies + dev->timeout_jiffies);
+ if (dev->sustain_framerate && !timer_pending(&dev->sustain_timer))
+ mod_timer(&dev->sustain_timer, jiffies
+ + dev->frame_jiffies * 3 / 2);
+}
+#ifdef HAVE_TIMER_SETUP
+static void sustain_timer_clb(struct timer_list *t)
+{
+ struct v4l2_loopback_device *dev = from_timer(dev, t, sustain_timer);
+#else
+static void sustain_timer_clb(unsigned long nr)
+{
+ struct v4l2_loopback_device *dev = devs[nr];
+#endif
+ spin_lock(&dev->lock);
+ if (dev->sustain_framerate) {
+ dev->reread_count++;
+ pr_debug("reread: %d %d\n",
+ dev->write_position, dev->reread_count);
+ if (dev->reread_count == 1)
+ mod_timer(&dev->sustain_timer, jiffies
+ + max(1UL, dev->frame_jiffies / 2));
+ else
+ mod_timer(&dev->sustain_timer, jiffies
+ + dev->frame_jiffies);
+ wake_up_all(&dev->read_event);
+ }
+ spin_unlock(&dev->lock);
+}
+#ifdef HAVE_TIMER_SETUP
+static void timeout_timer_clb(struct timer_list *t)
+{
+ struct v4l2_loopback_device *dev = from_timer(dev, t, timeout_timer);
+#else
+static void timeout_timer_clb(unsigned long nr)
+{
+ struct v4l2_loopback_device *dev = devs[nr];
+#endif
+ spin_lock(&dev->lock);
+ if (dev->timeout_jiffies > 0) {
+ dev->timeout_happened = 1;
+ mod_timer(&dev->timeout_timer, jiffies + dev->timeout_jiffies);
+ wake_up_all(&dev->read_event);
+ }
+ spin_unlock(&dev->lock);
+}
+
+/* init loopback main structure */
+static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr)
+{
+ int ret;
+ struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+ "v4l2loopback-%03d", nr);
+ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+ if (ret)
+ return ret;
+
+ MARK();
+ dev->vdev = video_device_alloc();
+ if (dev->vdev == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ video_set_drvdata(dev->vdev,
+ kzalloc(sizeof(struct v4l2loopback_private), GFP_KERNEL));
+ if (video_get_drvdata(dev->vdev) == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ ((struct v4l2loopback_private *)video_get_drvdata
+ (dev->vdev))->devicenr = nr;
+
+ init_vdev(dev->vdev, nr);
+ dev->vdev->v4l2_dev = &dev->v4l2_dev;
+ init_capture_param(&dev->capture_param);
+ set_timeperframe(dev, &dev->capture_param.timeperframe);
+ dev->keep_format = 0;
+ dev->sustain_framerate = 0;
+ dev->buffers_number = max_buffers;
+ dev->used_buffers = max_buffers;
+ dev->max_openers = max_openers;
+ dev->write_position = 0;
+ spin_lock_init(&dev->lock);
+ INIT_LIST_HEAD(&dev->outbufs_list);
+ if (list_empty(&dev->outbufs_list)) {
+ int i;
+
+ for (i = 0; i < dev->used_buffers; ++i)
+ list_add_tail(&dev->buffers[i].list_head,
+ &dev->outbufs_list);
+ }
+ memset(dev->bufpos2index, 0, sizeof(dev->bufpos2index));
+ atomic_set(&dev->open_count, 0);
+ dev->ready_for_capture = 0;
+ dev->ready_for_output = 1;
+ dev->announce_all_caps = (!exclusive_caps[nr]);
+
+ dev->buffer_size = 0;
+ dev->image = NULL;
+ dev->imagesize = 0;
+#ifdef HAVE_TIMER_SETUP
+ timer_setup(&dev->sustain_timer, sustain_timer_clb, 0);
+ timer_setup(&dev->timeout_timer, timeout_timer_clb, 0);
+#else
+ setup_timer(&dev->sustain_timer, sustain_timer_clb, nr);
+ setup_timer(&dev->timeout_timer, timeout_timer_clb, nr);
+#endif
+ dev->reread_count = 0;
+ dev->timeout_jiffies = 0;
+ dev->timeout_image = NULL;
+ dev->timeout_happened = 0;
+
+ ret = v4l2_ctrl_handler_init(hdl, 1);
+ if (ret)
+ goto error;
+ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_keepformat, NULL);
+ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_sustainframerate, NULL);
+ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_timeout, NULL);
+ v4l2_ctrl_new_custom(hdl, &v4l2loopback_ctrl_timeoutimageio, NULL);
+ if (hdl->error) {
+ ret = hdl->error;
+ goto error;
+ }
+ dev->v4l2_dev.ctrl_handler = hdl;
+
+ /* FIXME set buffers to 0 */
+
+ /* Set initial format */
+ dev->pix_format.width = 0; /* V4L2LOOPBACK_SIZE_DEFAULT_WIDTH; */
+ dev->pix_format.height = 0; /* V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT; */
+ dev->pix_format.pixelformat = formats[0].fourcc;
+ dev->pix_format.colorspace =
+ V4L2_COLORSPACE_SRGB; /* do we need to set this ? */
+ dev->pix_format.field = V4L2_FIELD_NONE;
+
+ dev->buffer_size = PAGE_ALIGN(dev->pix_format.sizeimage);
+ pr_debug("buffer_size = %ld (=%d)\n",
+ dev->buffer_size, dev->pix_format.sizeimage);
+ allocate_buffers(dev);
+
+ init_waitqueue_head(&dev->read_event);
+ init_waitqueue_head(&dev->write_event);
+
+ MARK();
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev->vdev);
+ return ret;
+
+};
+
+/* LINUX KERNEL */
+static const struct v4l2_file_operations v4l2_loopback_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_loopback_open,
+ .release = v4l2_loopback_close,
+ .read = v4l2_loopback_read,
+ .write = v4l2_loopback_write,
+ .poll = v4l2_loopback_poll,
+ .mmap = v4l2_loopback_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops = {
+ .vidioc_querycap = &vidioc_querycap,
+ .vidioc_enum_framesizes = &vidioc_enum_framesizes,
+ .vidioc_enum_frameintervals = &vidioc_enum_frameintervals,
+
+#ifndef HAVE__V4L2_CTRLS
+ .vidioc_queryctrl = &vidioc_queryctrl,
+ .vidioc_g_ctrl = &vidioc_g_ctrl,
+ .vidioc_s_ctrl = &vidioc_s_ctrl,
+#endif /* HAVE__V4L2_CTRLS */
+
+ .vidioc_enum_output = &vidioc_enum_output,
+ .vidioc_g_output = &vidioc_g_output,
+ .vidioc_s_output = &vidioc_s_output,
+
+ .vidioc_enum_input = &vidioc_enum_input,
+ .vidioc_g_input = &vidioc_g_input,
+ .vidioc_s_input = &vidioc_s_input,
+
+ .vidioc_enum_fmt_vid_cap = &vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_vid_cap = &vidioc_g_fmt_cap,
+ .vidioc_s_fmt_vid_cap = &vidioc_s_fmt_cap,
+ .vidioc_try_fmt_vid_cap = &vidioc_try_fmt_cap,
+
+ .vidioc_enum_fmt_vid_out = &vidioc_enum_fmt_out,
+ .vidioc_s_fmt_vid_out = &vidioc_s_fmt_out,
+ .vidioc_g_fmt_vid_out = &vidioc_g_fmt_out,
+ .vidioc_try_fmt_vid_out = &vidioc_try_fmt_out,
+
+#ifdef V4L2L_OVERLAY
+ .vidioc_s_fmt_vid_overlay = &vidioc_s_fmt_overlay,
+ .vidioc_g_fmt_vid_overlay = &vidioc_g_fmt_overlay,
+#endif
+
+#ifdef V4L2LOOPBACK_WITH_STD
+ .vidioc_s_std = &vidioc_s_std,
+ .vidioc_g_std = &vidioc_g_std,
+ .vidioc_querystd = &vidioc_querystd,
+#endif /* V4L2LOOPBACK_WITH_STD */
+
+ .vidioc_g_parm = &vidioc_g_parm,
+ .vidioc_s_parm = &vidioc_s_parm,
+
+ .vidioc_reqbufs = &vidioc_reqbufs,
+ .vidioc_querybuf = &vidioc_querybuf,
+ .vidioc_qbuf = &vidioc_qbuf,
+ .vidioc_dqbuf = &vidioc_dqbuf,
+
+ .vidioc_streamon = &vidioc_streamon,
+ .vidioc_streamoff = &vidioc_streamoff,
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = &vidiocgmbuf,
+#endif
+
+};
+
+static void zero_devices(void)
+{
+ int i;
+
+ MARK();
+ for (i = 0; i < MAX_DEVICES; i++)
+ devs[i] = NULL;
+}
+
+static void free_devices(void)
+{
+ int i;
+
+ MARK();
+ for (i = 0; i < devices; i++) {
+ if (devs[i] != NULL) {
+ free_buffers(devs[i]);
+ v4l2loopback_remove_sysfs(devs[i]->vdev);
+ kfree(video_get_drvdata(devs[i]->vdev));
+ video_unregister_device(devs[i]->vdev);
+ v4l2_device_unregister(&devs[i]->v4l2_dev);
+ v4l2_ctrl_handler_free(&devs[i]->ctrl_handler);
+ kfree(devs[i]);
+ devs[i] = NULL;
+ }
+ }
+}
+
+static int __init v4l2loopback_init_module(void)
+{
+ int ret;
+ int i;
+
+ MARK();
+ zero_devices();
+ if (devices < 0) {
+ devices = 1;
+
+ /* try guessing the devices from the "video_nr" parameter */
+ for (i = MAX_DEVICES - 1; i >= 0; i--) {
+ if (video_nr[i] >= 0) {
+ devices = i + 1;
+ break;
+ }
+ }
+ }
+
+ if (devices > MAX_DEVICES) {
+ devices = MAX_DEVICES;
+ pr_debug(
+ "v4l2loopback: number of devices is limited to: %d\n"
+ , MAX_DEVICES);
+ }
+
+ if (max_buffers > MAX_BUFFERS) {
+ max_buffers = MAX_BUFFERS;
+ pr_debug(
+ "v4l2loopback: number of buffers is limited to: %d\n"
+ , MAX_BUFFERS);
+ }
+
+ if (max_openers < 0) {
+ pr_debug(
+ "v4l2loopback: allowing %d openers rather than %d\n"
+ , 2, max_openers);
+ max_openers = 2;
+ }
+
+ if (max_width < 1) {
+ max_width = V4L2LOOPBACK_SIZE_MAX_WIDTH;
+ pr_debug("v4l2loopback: using max_width %d\n", max_width);
+ }
+ if (max_height < 1) {
+ max_height = V4L2LOOPBACK_SIZE_MAX_HEIGHT;
+ pr_debug("v4l2loopback: using max_height %d\n", max_height);
+ }
+
+ /* kfree on module release */
+ for (i = 0; i < devices; i++) {
+ pr_debug("creating v4l2loopback-device #%d\n", i);
+ devs[i] = kzalloc(sizeof(*devs[i]), GFP_KERNEL);
+ if (devs[i] == NULL) {
+ free_devices();
+ return -ENOMEM;
+ }
+ ret = v4l2_loopback_init(devs[i], i);
+ if (ret < 0) {
+ free_devices();
+ return ret;
+ }
+ /* register the device -> it creates /dev/video* */
+ if (video_register_device(devs[i]->vdev,
+ VFL_TYPE_GRABBER, video_nr[i]) < 0) {
+ video_device_release(devs[i]->vdev);
+ pr_err(
+ "v4l2loopback: failed video_register_device()\n");
+ free_devices();
+ return -EFAULT;
+ }
+ v4l2loopback_create_sysfs(devs[i]->vdev);
+ }
+
+ pr_info("module installed\n");
+
+ pr_info("v4l2loopback driver version %d.%d.%d loaded\n",
+ (V4L2LOOPBACK_VERSION_CODE >> 16) & 0xff,
+ (V4L2LOOPBACK_VERSION_CODE >> 8) & 0xff,
+ (V4L2LOOPBACK_VERSION_CODE) & 0xff);
+
+ return 0;
+}
+
+static void v4l2loopback_cleanup_module(void)
+{
+ MARK();
+ /* unregister the device -> it deletes /dev/video* */
+ free_devices();
+ pr_info("module removed\n");
+}
+
+#ifdef MODULE
+int __init init_module(void)
+{
+ return v4l2loopback_init_module();
+}
+void __exit cleanup_module(void)
+{
+ return v4l2loopback_cleanup_module();
+}
+#else
+late_initcall(v4l2loopback_init_module);
+#endif
+
+
+
+/*
+ * fake usage of unused functions
+ */
+#ifdef HAVE__V4L2_CTRLS
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *q) __attribute__ ((unused));
+static int vidioc_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *c) __attribute__ ((unused));
+static int vidioc_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *c) __attribute__ ((unused));
+#endif /* HAVE__V4L2_CTRLS */
diff --git a/drivers/media/v4l2loopback-master/v4l2loopback_formats.h b/drivers/media/v4l2loopback-master/v4l2loopback_formats.h
new file mode 100644
index 000000000000..e844d8a0a7d4
--- /dev/null
+++ b/drivers/media/v4l2loopback-master/v4l2loopback_formats.h
@@ -0,0 +1,419 @@
+
+/* here come the packed formats */
+{
+ .name = "32 bpp RGB, le",
+ .fourcc = V4L2_PIX_FMT_BGR32,
+ .depth = 32,
+ .flags = 0,
+},
+{
+ .name = "32 bpp RGB, be",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ .flags = 0,
+},
+{
+ .name = "24 bpp RGB, le",
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .depth = 24,
+ .flags = 0,
+},
+{
+ .name = "24 bpp RGB, be",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .depth = 24,
+ .flags = 0,
+},
+#ifdef V4L2_PIX_FMT_RGB332
+{
+ .name = "8 bpp RGB-3-3-2",
+ .fourcc = V4L2_PIX_FMT_RGB332,
+ .depth = 8,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_RGB332 */
+#ifdef V4L2_PIX_FMT_RGB444
+{
+ .name = "16 bpp RGB (xxxxrrrr ggggbbbb)",
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .depth = 16,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_RGB444 */
+#ifdef V4L2_PIX_FMT_RGB555
+{
+ .name = "16 bpp RGB-5-5-5",
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .depth = 16,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_RGB555 */
+#ifdef V4L2_PIX_FMT_RGB565
+{
+ .name = "16 bpp RGB-5-6-5",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_RGB565 */
+#ifdef V4L2_PIX_FMT_RGB555X
+{
+ .name = "16 bpp RGB-5-5-5 BE",
+ .fourcc = V4L2_PIX_FMT_RGB555X,
+ .depth = 16,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_RGB555X */
+#ifdef V4L2_PIX_FMT_RGB565X
+{
+ .name = "16 bpp RGB-5-6-5 BE",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = 16,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_RGB565X */
+#ifdef V4L2_PIX_FMT_BGR666
+{
+ .name = "18 bpp BGR-6-6-6",
+ .fourcc = V4L2_PIX_FMT_BGR666,
+ .depth = 18,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_BGR666 */
+{
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .flags = 0,
+},
+{
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ .flags = 0,
+},
+#ifdef V4L2_PIX_FMT_YVYU
+{
+ .name = "4:2:2, packed YVYU",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = 16,
+ .flags = 0,
+},
+#endif
+#ifdef V4L2_PIX_FMT_VYUY
+{
+ .name = "4:2:2, packed VYUY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = 16,
+ .flags = 0,
+},
+#endif
+{
+ .name = "4:2:2, packed YYUV",
+ .fourcc = V4L2_PIX_FMT_YYUV,
+ .depth = 16,
+ .flags = 0,
+},
+{
+ .name = "YUV-8-8-8-8",
+ .fourcc = V4L2_PIX_FMT_YUV32,
+ .depth = 32,
+ .flags = 0,
+},
+{
+ .name = "8 bpp, Greyscale",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = 8,
+ .flags = 0,
+},
+#ifdef V4L2_PIX_FMT_Y4
+{
+ .name = "4 bpp Greyscale",
+ .fourcc = V4L2_PIX_FMT_Y4,
+ .depth = 4,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_Y4 */
+#ifdef V4L2_PIX_FMT_Y6
+{
+ .name = "6 bpp Greyscale",
+ .fourcc = V4L2_PIX_FMT_Y6,
+ .depth = 6,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_Y6 */
+#ifdef V4L2_PIX_FMT_Y10
+{
+ .name = "10 bpp Greyscale",
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .depth = 10,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_Y10 */
+#ifdef V4L2_PIX_FMT_Y12
+{
+ .name = "12 bpp Greyscale",
+ .fourcc = V4L2_PIX_FMT_Y12,
+ .depth = 12,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_Y12 */
+{
+ .name = "16 bpp, Greyscale",
+ .fourcc = V4L2_PIX_FMT_Y16,
+ .depth = 16,
+ .flags = 0,
+},
+#ifdef V4L2_PIX_FMT_YUV444
+{
+ .name = "16 bpp xxxxyyyy uuuuvvvv",
+ .fourcc = V4L2_PIX_FMT_YUV444,
+ .depth = 16,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_YUV444 */
+#ifdef V4L2_PIX_FMT_YUV555
+{
+ .name = "16 bpp YUV-5-5-5",
+ .fourcc = V4L2_PIX_FMT_YUV555,
+ .depth = 16,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_YUV555 */
+#ifdef V4L2_PIX_FMT_YUV565
+{
+ .name = "16 bpp YUV-5-6-5",
+ .fourcc = V4L2_PIX_FMT_YUV565,
+ .depth = 16,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_YUV565 */
+
+ /* bayer formats */
+#ifdef V4L2_PIX_FMT_SRGGB8
+{
+ .name = "Bayer RGGB 8bit",
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .depth = 8,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_SRGGB8 */
+#ifdef V4L2_PIX_FMT_SGRBG8
+{
+ .name = "Bayer GRBG 8bit",
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .depth = 8,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_SGRBG8 */
+#ifdef V4L2_PIX_FMT_SGBRG8
+{
+ .name = "Bayer GBRG 8bit",
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .depth = 8,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_SGBRG8 */
+#ifdef V4L2_PIX_FMT_SBGGR8
+{
+ .name = "Bayer BA81 8bit",
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .depth = 8,
+ .flags = 0,
+},
+#endif /* V4L2_PIX_FMT_SBGGR8 */
+
+
+
+ /* here come the planar formats */
+{
+ .name = "4:1:0, planar, Y-Cr-Cb",
+ .fourcc = V4L2_PIX_FMT_YVU410,
+ .depth = 9,
+ .flags = FORMAT_FLAGS_PLANAR,
+},
+{
+ .name = "4:2:0, planar, Y-Cr-Cb",
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .depth = 12,
+ .flags = FORMAT_FLAGS_PLANAR,
+},
+{
+ .name = "4:1:0, planar, Y-Cb-Cr",
+ .fourcc = V4L2_PIX_FMT_YUV410,
+ .depth = 9,
+ .flags = FORMAT_FLAGS_PLANAR,
+},
+{
+ .name = "4:2:0, planar, Y-Cb-Cr",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = 12,
+ .flags = FORMAT_FLAGS_PLANAR,
+},
+#ifdef V4L2_PIX_FMT_YUV422P
+{
+ .name = "16 bpp YVU422 planar",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .depth = 16,
+ .flags = FORMAT_FLAGS_PLANAR,
+},
+#endif /* V4L2_PIX_FMT_YUV422P */
+#ifdef V4L2_PIX_FMT_YUV411P
+{
+ .name = "16 bpp YVU411 planar",
+ .fourcc = V4L2_PIX_FMT_YUV411P,
+ .depth = 16,
+ .flags = FORMAT_FLAGS_PLANAR,
+},
+#endif /* V4L2_PIX_FMT_YUV411P */
+#ifdef V4L2_PIX_FMT_Y41P
+{
+ .name = "12 bpp YUV 4:1:1",
+ .fourcc = V4L2_PIX_FMT_Y41P,
+ .depth = 12,
+ .flags = FORMAT_FLAGS_PLANAR,
+},
+#endif /* V4L2_PIX_FMT_Y41P */
+#ifdef V4L2_PIX_FMT_NV12
+{
+ .name = "12 bpp Y/CbCr 4:2:0 ",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = 12,
+ .flags = FORMAT_FLAGS_PLANAR,
+},
+#endif /* V4L2_PIX_FMT_NV12 */
+
+ /* here come the compressed formats */
+
+#ifdef V4L2_PIX_FMT_MJPEG
+{
+ .name = "Motion-JPEG",
+ .fourcc = V4L2_PIX_FMT_MJPEG,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_MJPEG */
+#ifdef V4L2_PIX_FMT_JPEG
+{
+ .name = "JFIF JPEG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_JPEG */
+#ifdef V4L2_PIX_FMT_DV
+{
+ .name = "DV1394",
+ .fourcc = V4L2_PIX_FMT_DV,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_DV */
+#ifdef V4L2_PIX_FMT_MPEG
+{
+ .name = "MPEG-1/2/4 Multiplexed",
+ .fourcc = V4L2_PIX_FMT_MPEG,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_MPEG */
+#ifdef V4L2_PIX_FMT_H264
+{
+ .name = "H264 with start codes",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_H264 */
+#ifdef V4L2_PIX_FMT_H264_NO_SC
+{
+ .name = "H264 without start codes",
+ .fourcc = V4L2_PIX_FMT_H264_NO_SC,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_H264_NO_SC */
+#ifdef V4L2_PIX_FMT_H264_MVC
+{
+ .name = "H264 MVC",
+ .fourcc = V4L2_PIX_FMT_H264_MVC,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_H264_MVC */
+#ifdef V4L2_PIX_FMT_H263
+{
+ .name = "H263",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_H263 */
+#ifdef V4L2_PIX_FMT_MPEG1
+{
+ .name = "MPEG-1 ES",
+ .fourcc = V4L2_PIX_FMT_MPEG1,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_MPEG1 */
+#ifdef V4L2_PIX_FMT_MPEG2
+{
+ .name = "MPEG-2 ES",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_MPEG2 */
+#ifdef V4L2_PIX_FMT_MPEG4
+{
+ .name = "MPEG-4 part 2 ES",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_MPEG4 */
+#ifdef V4L2_PIX_FMT_XVID
+{
+ .name = "Xvid",
+ .fourcc = V4L2_PIX_FMT_XVID,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_XVID */
+#ifdef V4L2_PIX_FMT_VC1_ANNEX_G
+{
+ .name = "SMPTE 421M Annex G compliant stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_VC1_ANNEX_G */
+#ifdef V4L2_PIX_FMT_VC1_ANNEX_L
+{
+ .name = "SMPTE 421M Annex L compliant stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_VC1_ANNEX_L */
+#ifdef V4L2_PIX_FMT_VP8
+{
+ .name = "VP8",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+#endif /* V4L2_PIX_FMT_VP8 */
+{
+ .name = "VP9",
+ .fourcc = V4L2_PIX_FMT_VP9,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
+{
+ .name = "HEVC",
+ .fourcc = V4L2_PIX_FMT_HEVC,
+ .depth = 32,
+ .flags = FORMAT_FLAGS_COMPRESSED,
+},
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index fefbe4cfa61d..1263cfd8b4d2 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -259,7 +259,7 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
mutex_unlock(&ab8500->lock);
dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
- return ret;
+ return (ret < 0) ? ret : 0;
}
static int ab8500_get_register(struct device *dev, u8 bank,
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 12099b09a9a7..e71b9f23379d 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -2610,7 +2610,7 @@ static struct irq_chip prcmu_irq_chip = {
.irq_unmask = prcmu_irq_unmask,
};
-static __init char *fw_project_name(u32 project)
+static char *fw_project_name(u32 project)
{
switch (project) {
case PRCMU_FW_PROJECT_U8500:
@@ -2758,7 +2758,7 @@ void __init db8500_prcmu_early_init(u32 phy_base, u32 size)
INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
}
-static void __init init_prcm_registers(void)
+static void init_prcm_registers(void)
{
u32 val;
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 3f9f4c874d2a..8d74806b83c1 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -274,7 +274,9 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
mc13xxx->adcflags |= MC13XXX_ADC_WORKING;
- mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
+ ret = mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
+ if (ret)
+ goto out;
adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2;
adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC;
diff --git a/drivers/mfd/qcom_rpm.c b/drivers/mfd/qcom_rpm.c
index a867cc91657e..27486f278201 100644
--- a/drivers/mfd/qcom_rpm.c
+++ b/drivers/mfd/qcom_rpm.c
@@ -570,6 +570,10 @@ static int qcom_rpm_probe(struct platform_device *pdev)
return -EFAULT;
}
+ writel(fw_version[0], RPM_CTRL_REG(rpm, 0));
+ writel(fw_version[1], RPM_CTRL_REG(rpm, 1));
+ writel(fw_version[2], RPM_CTRL_REG(rpm, 2));
+
dev_info(&pdev->dev, "RPM firmware %u.%u.%u\n", fw_version[0],
fw_version[1],
fw_version[2]);
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c
index 4a0f076c91ba..faf8ce5be576 100644
--- a/drivers/mfd/ti_am335x_tscadc.c
+++ b/drivers/mfd/ti_am335x_tscadc.c
@@ -279,8 +279,9 @@ static int ti_tscadc_probe(struct platform_device *pdev)
cell->pdata_size = sizeof(tscadc);
}
- err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells,
- tscadc->used_cells, NULL, 0, NULL);
+ err = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
+ tscadc->cells, tscadc->used_cells, NULL,
+ 0, NULL);
if (err < 0)
goto err_disable_clk;
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 831696ee2472..90732a655d57 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -982,7 +982,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
* letting it generate the right frequencies for USB, MADC, and
* other purposes.
*/
-static inline int __init protect_pm_master(void)
+static inline int protect_pm_master(void)
{
int e = 0;
@@ -991,7 +991,7 @@ static inline int __init protect_pm_master(void)
return e;
}
-static inline int __init unprotect_pm_master(void)
+static inline int unprotect_pm_master(void)
{
int e = 0;
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
index 2bb2d0467a92..c47efe6dcb01 100644
--- a/drivers/mfd/wm5110-tables.c
+++ b/drivers/mfd/wm5110-tables.c
@@ -1622,6 +1622,7 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */
{ 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */
{ 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */
+ { 0x00000EE3, 0x4000 }, /* R3811 - ASRC_RATE2 */
{ 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */
{ 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */
{ 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */
@@ -2877,6 +2878,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_ASRC_ENABLE:
case ARIZONA_ASRC_STATUS:
case ARIZONA_ASRC_RATE1:
+ case ARIZONA_ASRC_RATE2:
case ARIZONA_ISRC_1_CTRL_1:
case ARIZONA_ISRC_1_CTRL_2:
case ARIZONA_ISRC_1_CTRL_3:
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index aad3243a48fc..e03ec74f3fb0 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1451,6 +1451,7 @@ static int mmc_spi_probe(struct spi_device *spi)
if (status != 0)
goto fail_add_host;
}
+ mmc_detect_change(mmc, 0);
dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n",
dev_name(&mmc->class_dev),
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 2dea39b5cb0b..e2414f2d7ba9 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -712,7 +712,7 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct dsa_switch *ds,
if (s->sizeof_stat == 8)
_mv88e6xxx_stats_read(ds, s->reg + 1, &high);
}
- value = (((u64)high) << 16) | low;
+ value = (((u64)high) << 32) | low;
return value;
}
diff --git a/drivers/net/ethernet/altera/altera_msgdma.c b/drivers/net/ethernet/altera/altera_msgdma.c
index 0fb986ba3290..0ae723f75341 100644
--- a/drivers/net/ethernet/altera/altera_msgdma.c
+++ b/drivers/net/ethernet/altera/altera_msgdma.c
@@ -145,7 +145,8 @@ u32 msgdma_tx_completions(struct altera_tse_private *priv)
& 0xffff;
if (inuse) { /* Tx FIFO is not empty */
- ready = priv->tx_prod - priv->tx_cons - inuse - 1;
+ ready = max_t(int,
+ priv->tx_prod - priv->tx_cons - inuse - 1, 0);
} else {
/* Check for buffered last packet */
status = csrrd32(priv->tx_dma_csr, msgdma_csroffs(status));
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
index fe644823ceaf..bb51f124d8c7 100644
--- a/drivers/net/ethernet/altera/altera_tse_main.c
+++ b/drivers/net/ethernet/altera/altera_tse_main.c
@@ -716,8 +716,10 @@ static struct phy_device *connect_local_phy(struct net_device *dev)
phydev = phy_connect(dev, phy_id_fmt, &altera_tse_adjust_link,
priv->phy_iface);
- if (IS_ERR(phydev))
+ if (IS_ERR(phydev)) {
netdev_err(dev, "Could not attach to PHY\n");
+ phydev = NULL;
+ }
} else {
int ret;
diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c
index 2ff465848b65..097a0bf592ab 100644
--- a/drivers/net/ethernet/atheros/atlx/atl2.c
+++ b/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -1338,13 +1338,11 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *netdev;
struct atl2_adapter *adapter;
- static int cards_found;
+ static int cards_found = 0;
unsigned long mmio_start;
int mmio_len;
int err;
- cards_found = 0;
-
err = pci_enable_device(pdev);
if (err)
return err;
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 143b9a384af8..53b3c1a5851c 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -126,6 +126,10 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev,
priv->rx_chk_en = !!(wanted & NETIF_F_RXCSUM);
reg = rxchk_readl(priv, RXCHK_CONTROL);
+ /* Clear L2 header checks, which would prevent BPDUs
+ * from being received.
+ */
+ reg &= ~RXCHK_L2_HDR_DIS;
if (priv->rx_chk_en)
reg |= RXCHK_EN;
else
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index fea8116da06a..00bd7be85679 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -330,6 +330,12 @@ normal_tx:
}
length >>= 9;
+ if (unlikely(length >= ARRAY_SIZE(bnxt_lhint_arr))) {
+ dev_warn_ratelimited(&pdev->dev, "Dropped oversize %d bytes TX packet.\n",
+ skb->len);
+ i = 0;
+ goto tx_dma_error;
+ }
flags |= bnxt_lhint_arr[length];
txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index 1a16c0307b47..bd36fbe81ad2 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -188,12 +188,10 @@ static void hns_ae_put_handle(struct hnae_handle *handle)
struct hnae_vf_cb *vf_cb = hns_ae_get_vf_cb(handle);
int i;
- vf_cb->mac_cb = NULL;
-
- kfree(vf_cb);
-
for (i = 0; i < handle->q_num; i++)
hns_ae_get_ring_pair(handle->qs[i])->used_by_vf = 0;
+
+ kfree(vf_cb);
}
static void hns_ae_ring_enable_all(struct hnae_handle *handle, int val)
diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c
index 37491c85bc42..6ff13c559e52 100644
--- a/drivers/net/ethernet/hisilicon/hns_mdio.c
+++ b/drivers/net/ethernet/hisilicon/hns_mdio.c
@@ -319,7 +319,7 @@ static int hns_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
}
hns_mdio_cmd_write(mdio_dev, is_c45,
- MDIO_C45_WRITE_ADDR, phy_id, devad);
+ MDIO_C45_READ, phy_id, devad);
}
/* Step 5: waitting for MDIO_COMMAND_REG 's mdio_start==0,*/
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 61a9ab4fe047..70b3253e7ed5 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1238,7 +1238,6 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
struct iphdr *iph;
u16 mss = 0;
-restart_poll:
while (frames_processed < budget) {
if (!ibmveth_rxq_pending_buffer(adapter))
break;
@@ -1336,7 +1335,6 @@ restart_poll:
napi_reschedule(napi)) {
lpar_rc = h_vio_signal(adapter->vdev->unit_address,
VIO_IRQ_DISABLE);
- goto restart_poll;
}
}
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 4182290fdbcf..82f080a5ed5c 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -2884,7 +2884,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
ret = mv643xx_eth_shared_of_probe(pdev);
if (ret)
- return ret;
+ goto err_put_clk;
pd = dev_get_platdata(&pdev->dev);
msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
@@ -2892,6 +2892,11 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
infer_hw_params(msp);
return 0;
+
+err_put_clk:
+ if (!IS_ERR(msp->clk))
+ clk_disable_unprepare(msp->clk);
+ return ret;
}
static int mv643xx_eth_shared_remove(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 4b97aa24559a..5cc05df69a86 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -46,6 +46,7 @@
#include <linux/mii.h>
#include <linux/of_device.h>
#include <linux/of_net.h>
+#include <linux/dmi.h>
#include <asm/irq.h>
@@ -93,7 +94,7 @@ static int copybreak __read_mostly = 128;
module_param(copybreak, int, 0);
MODULE_PARM_DESC(copybreak, "Receive copy threshold");
-static int disable_msi = 0;
+static int disable_msi = -1;
module_param(disable_msi, int, 0);
MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
@@ -4923,6 +4924,24 @@ static const char *sky2_name(u8 chipid, char *buf, int sz)
return buf;
}
+static const struct dmi_system_id msi_blacklist[] = {
+ {
+ .ident = "Dell Inspiron 1545",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1545"),
+ },
+ },
+ {
+ .ident = "Gateway P-79",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Gateway"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "P-79"),
+ },
+ },
+ {}
+};
+
static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *dev, *dev1;
@@ -5034,6 +5053,9 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_pci;
}
+ if (disable_msi == -1)
+ disable_msi = !!dmi_check_system(msi_blacklist);
+
if (!disable_msi && pci_enable_msi(pdev) == 0) {
err = sky2_test_msi(hw);
if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index fc222df47aa9..9e104dcfa9dd 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -2636,6 +2636,7 @@ void mlx4_cmd_use_polling(struct mlx4_dev *dev)
down(&priv->cmd.event_sem);
kfree(priv->cmd.context);
+ priv->cmd.context = NULL;
up(&priv->cmd.poll_sem);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 82bf1b539d87..ac7c64bae2a5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -725,13 +725,27 @@ static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
return 0;
}
#endif
+
+#define short_frame(size) ((size) <= ETH_ZLEN + ETH_FCS_LEN)
+
static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va,
netdev_features_t dev_features)
{
__wsum hw_checksum = 0;
+ void *hdr;
+
+ /* CQE csum doesn't cover padding octets in short ethernet
+ * frames. And the pad field is appended prior to calculating
+ * and appending the FCS field.
+ *
+ * Detecting these padded frames requires to verify and parse
+ * IP headers, so we simply force all those small frames to skip
+ * checksum complete.
+ */
+ if (short_frame(skb->len))
+ return -EINVAL;
- void *hdr = (u8 *)va + sizeof(struct ethhdr);
-
+ hdr = (u8 *)va + sizeof(struct ethhdr);
hw_checksum = csum_unfold((__force __sum16)cqe->checksum);
if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK) &&
@@ -851,6 +865,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
(cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_L2_TUNNEL));
if (likely(dev->features & NETIF_F_RXCSUM)) {
+ /* TODO: For IP non TCP/UDP packets when csum complete is
+ * not an option (not supported or any other reason) we can
+ * actually check cqe IPOK status bit and report
+ * CHECKSUM_UNNECESSARY rather than CHECKSUM_NONE
+ */
if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
MLX4_CQE_STATUS_UDP)) {
if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 7911dc3da98e..37dfdb1329f4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -2652,13 +2652,13 @@ static int qp_get_mtt_size(struct mlx4_qp_context *qpc)
int total_pages;
int total_mem;
int page_offset = (be32_to_cpu(qpc->params2) >> 6) & 0x3f;
+ int tot;
sq_size = 1 << (log_sq_size + log_sq_sride + 4);
rq_size = (srq|rss|xrc) ? 0 : (1 << (log_rq_size + log_rq_stride + 4));
total_mem = sq_size + rq_size;
- total_pages =
- roundup_pow_of_two((total_mem + (page_offset << 6)) >>
- page_shift);
+ tot = (total_mem + (page_offset << 6)) >> page_shift;
+ total_pages = !tot ? 1 : roundup_pow_of_two(tot);
return total_pages;
}
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index f735dfcb64ae..29d31eb995d7 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -453,7 +453,7 @@ static int ravb_dmac_init(struct net_device *ndev)
ravb_write(ndev, RCR_EFFS | RCR_ENCF | RCR_ETS0 | 0x18000000, RCR);
/* Set FIFO size */
- ravb_write(ndev, TGC_TQP_AVBMODE1 | 0x00222200, TGC);
+ ravb_write(ndev, TGC_TQP_AVBMODE1 | 0x00112200, TGC);
/* Timestamp enable */
ravb_write(ndev, TCCR_TFEN, TCCR);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 0cd3ecff768b..398b08e07149 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -535,8 +535,10 @@ static int rk_gmac_init(struct platform_device *pdev, void *priv)
int ret;
ret = phy_power_on(bsp_priv, true);
- if (ret)
+ if (ret) {
+ gmac_clk_enable(bsp_priv, false);
return ret;
+ }
ret = gmac_clk_enable(bsp_priv, true);
if (ret)
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index a9268db4e349..ae02ce17c505 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -389,7 +389,12 @@ static int ipvlan_nl_changelink(struct net_device *dev,
struct ipvl_dev *ipvlan = netdev_priv(dev);
struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev);
- if (data && data[IFLA_IPVLAN_MODE]) {
+ if (!data)
+ return 0;
+ if (!ns_capable(dev_net(ipvlan->phy_dev)->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (data[IFLA_IPVLAN_MODE]) {
u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
ipvlan_set_port_mode(port, nmode);
@@ -454,6 +459,8 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
struct ipvl_dev *tmp = netdev_priv(phy_dev);
phy_dev = tmp->phy_dev;
+ if (!ns_capable(dev_net(phy_dev)->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
} else if (!netif_is_ipvlan_port(phy_dev)) {
err = ipvlan_port_create(phy_dev);
if (err < 0)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 88cb4592b6fb..ccefba7af960 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -267,7 +267,6 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
err = device_register(&bus->dev);
if (err) {
pr_err("mii_bus %s failed to register\n", bus->id);
- put_device(&bus->dev);
return -EINVAL;
}
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 920391165f18..ba84fc3637b1 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -28,6 +28,7 @@
#include <linux/micrel_phy.h>
#include <linux/of.h>
#include <linux/clk.h>
+#include <uapi/linux/mdio.h>
/* Operation Mode Strap Override */
#define MII_KSZPHY_OMSO 0x16
@@ -287,6 +288,17 @@ static int kszphy_config_init(struct phy_device *phydev)
return 0;
}
+static int ksz8061_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_DEVID1, 0xB61A);
+ if (ret)
+ return ret;
+
+ return kszphy_config_init(phydev);
+}
+
static int ksz9021_load_values_from_of(struct phy_device *phydev,
const struct device_node *of_node,
u16 reg,
@@ -771,7 +783,7 @@ static struct phy_driver ksphy_driver[] = {
.phy_id_mask = 0x00fffff0,
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
- .config_init = kszphy_config_init,
+ .config_init = ksz8061_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = kszphy_ack_interrupt,
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 12a627fcc02c..53c1f2bd0f24 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -577,6 +577,7 @@ static void pptp_sock_destruct(struct sock *sk)
pppox_unbind_sock(sk);
}
skb_queue_purge(&sk->sk_receive_queue);
+ dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));
}
static int pptp_create(struct net *net, struct socket *sock, int kern)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 33ffb573fd67..267a90423154 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -247,17 +247,6 @@ static void __team_option_inst_mark_removed_port(struct team *team,
}
}
-static bool __team_option_inst_tmp_find(const struct list_head *opts,
- const struct team_option_inst *needle)
-{
- struct team_option_inst *opt_inst;
-
- list_for_each_entry(opt_inst, opts, tmp_list)
- if (opt_inst == needle)
- return true;
- return false;
-}
-
static int __team_options_register(struct team *team,
const struct team_option *option,
size_t option_count)
@@ -2447,7 +2436,6 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
int err = 0;
int i;
struct nlattr *nl_option;
- LIST_HEAD(opt_inst_list);
team = team_nl_team_get(info);
if (!team)
@@ -2463,6 +2451,7 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
struct nlattr *opt_attrs[TEAM_ATTR_OPTION_MAX + 1];
struct nlattr *attr;
struct nlattr *attr_data;
+ LIST_HEAD(opt_inst_list);
enum team_option_type opt_type;
int opt_port_ifindex = 0; /* != 0 for per-port options */
u32 opt_array_index = 0;
@@ -2566,23 +2555,17 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
if (err)
goto team_put;
opt_inst->changed = true;
-
- /* dumb/evil user-space can send us duplicate opt,
- * keep only the last one
- */
- if (__team_option_inst_tmp_find(&opt_inst_list,
- opt_inst))
- continue;
-
list_add(&opt_inst->tmp_list, &opt_inst_list);
}
if (!opt_found) {
err = -ENOENT;
goto team_put;
}
- }
- err = team_nl_send_event_options_get(team, &opt_inst_list);
+ err = team_nl_send_event_options_get(team, &opt_inst_list);
+ if (err)
+ break;
+ }
team_put:
team_nl_team_put(team);
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index a1536d0d83a9..a00335b3786e 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -305,6 +305,20 @@ static int lb_bpf_func_set(struct team *team, struct team_gsetter_ctx *ctx)
return 0;
}
+static void lb_bpf_func_free(struct team *team)
+{
+ struct lb_priv *lb_priv = get_lb_priv(team);
+ struct bpf_prog *fp;
+
+ if (!lb_priv->ex->orig_fprog)
+ return;
+
+ __fprog_destroy(lb_priv->ex->orig_fprog);
+ fp = rcu_dereference_protected(lb_priv->fp,
+ lockdep_is_held(&team->lock));
+ bpf_prog_destroy(fp);
+}
+
static int lb_tx_method_get(struct team *team, struct team_gsetter_ctx *ctx)
{
struct lb_priv *lb_priv = get_lb_priv(team);
@@ -619,6 +633,7 @@ static void lb_exit(struct team *team)
team_options_unregister(team, lb_options,
ARRAY_SIZE(lb_options));
+ lb_bpf_func_free(team);
cancel_delayed_work_sync(&lb_priv->ex->stats.refresh_dw);
free_percpu(lb_priv->pcpu_stats);
kfree(lb_priv->ex);
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 553908adf3c5..5dadfc508ade 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1229,6 +1229,14 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
}
}
+ rcu_read_lock();
+
+ if (unlikely(!(vxlan->dev->flags & IFF_UP))) {
+ rcu_read_unlock();
+ atomic_long_inc(&vxlan->dev->rx_dropped);
+ goto drop;
+ }
+
stats = this_cpu_ptr(vxlan->dev->tstats);
u64_stats_update_begin(&stats->syncp);
stats->rx_packets++;
@@ -1237,6 +1245,8 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
gro_cells_receive(&vxlan->gro_cells, skb);
+ rcu_read_unlock();
+
return;
drop:
if (tun_dst)
@@ -2312,6 +2322,8 @@ static void vxlan_uninit(struct net_device *dev)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
+ gro_cells_destroy(&vxlan->gro_cells);
+
vxlan_fdb_delete_default(vxlan);
free_percpu(dev->tstats);
@@ -3056,7 +3068,6 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
- gro_cells_destroy(&vxlan->gro_cells);
list_del(&vxlan->next);
unregister_netdevice_queue(dev, head);
}
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 0d1abcfec003..0f582117b0e3 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3002,7 +3002,7 @@ static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
goto out_err;
}
- genlmsg_reply(skb, info);
+ res = genlmsg_reply(skb, info);
break;
}
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 02db20b26749..d324ac308e6d 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1538,11 +1538,6 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s
skb_frag_size_set(&frags[i], len);
}
- /* Copied all the bits from the frag list -- free it. */
- skb_frag_list_init(skb);
- xenvif_skb_zerocopy_prepare(queue, nskb);
- kfree_skb(nskb);
-
/* Release all the original (foreign) frags. */
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
skb_frag_unref(skb, f);
@@ -1611,6 +1606,8 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
xenvif_fill_frags(queue, skb);
if (unlikely(skb_has_frag_list(skb))) {
+ struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
+ xenvif_skb_zerocopy_prepare(queue, nskb);
if (xenvif_handle_frag_list(queue, skb)) {
if (net_ratelimit())
netdev_err(queue->vif->dev,
@@ -1619,6 +1616,9 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
kfree_skb(skb);
continue;
}
+ /* Copied all the bits from the frag list -- free it. */
+ skb_frag_list_init(skb);
+ kfree_skb(nskb);
}
skb->dev = queue->vif->dev;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index bdce0679674c..02e6485c1ed5 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1377,7 +1377,7 @@ static struct superio_struct *find_superio(struct parport *p)
{
int i;
for (i = 0; i < NR_SUPERIOS; i++)
- if (superios[i].io != p->base)
+ if (superios[i].io == p->base)
return &superios[i];
return NULL;
}
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index b505b87661f8..07c4153e6f3d 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -656,7 +656,7 @@ static const char * const sd_a_groups[] = {
static const char * const sdxc_a_groups[] = {
"sdxc_d0_0_a", "sdxc_d13_0_a", "sdxc_d47_a", "sdxc_clk_a",
- "sdxc_cmd_a", "sdxc_d0_1_a", "sdxc_d0_13_1_a"
+ "sdxc_cmd_a", "sdxc_d0_1_a", "sdxc_d13_1_a"
};
static const char * const pcm_a_groups[] = {
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 988ebe9a6b90..953974b5a9a9 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -881,6 +881,7 @@ config INTEL_OAKTRAIL
config SAMSUNG_Q10
tristate "Samsung Q10 Extras"
depends on ACPI
+ depends on BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
---help---
This driver provides support for backlight control on Samsung Q10
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
index 92f88753bfed..2daf751c26c7 100644
--- a/drivers/regulator/s2mpa01.c
+++ b/drivers/regulator/s2mpa01.c
@@ -303,13 +303,13 @@ static const struct regulator_desc regulators[] = {
regulator_desc_ldo(2, STEP_50_MV),
regulator_desc_ldo(3, STEP_50_MV),
regulator_desc_ldo(4, STEP_50_MV),
- regulator_desc_ldo(5, STEP_50_MV),
+ regulator_desc_ldo(5, STEP_25_MV),
regulator_desc_ldo(6, STEP_25_MV),
regulator_desc_ldo(7, STEP_50_MV),
regulator_desc_ldo(8, STEP_50_MV),
regulator_desc_ldo(9, STEP_50_MV),
regulator_desc_ldo(10, STEP_50_MV),
- regulator_desc_ldo(11, STEP_25_MV),
+ regulator_desc_ldo(11, STEP_50_MV),
regulator_desc_ldo(12, STEP_50_MV),
regulator_desc_ldo(13, STEP_50_MV),
regulator_desc_ldo(14, STEP_50_MV),
@@ -320,11 +320,11 @@ static const struct regulator_desc regulators[] = {
regulator_desc_ldo(19, STEP_50_MV),
regulator_desc_ldo(20, STEP_50_MV),
regulator_desc_ldo(21, STEP_50_MV),
- regulator_desc_ldo(22, STEP_25_MV),
- regulator_desc_ldo(23, STEP_25_MV),
+ regulator_desc_ldo(22, STEP_50_MV),
+ regulator_desc_ldo(23, STEP_50_MV),
regulator_desc_ldo(24, STEP_50_MV),
regulator_desc_ldo(25, STEP_50_MV),
- regulator_desc_ldo(26, STEP_50_MV),
+ regulator_desc_ldo(26, STEP_25_MV),
regulator_desc_buck1_4(1),
regulator_desc_buck1_4(2),
regulator_desc_buck1_4(3),
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index b6d831b84e1d..47694dd515ab 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -372,7 +372,7 @@ static const struct regulator_desc s2mps11_regulators[] = {
regulator_desc_s2mps11_ldo(32, STEP_50_MV),
regulator_desc_s2mps11_ldo(33, STEP_50_MV),
regulator_desc_s2mps11_ldo(34, STEP_50_MV),
- regulator_desc_s2mps11_ldo(35, STEP_50_MV),
+ regulator_desc_s2mps11_ldo(35, STEP_25_MV),
regulator_desc_s2mps11_ldo(36, STEP_50_MV),
regulator_desc_s2mps11_ldo(37, STEP_50_MV),
regulator_desc_s2mps11_ldo(38, STEP_50_MV),
@@ -382,8 +382,8 @@ static const struct regulator_desc s2mps11_regulators[] = {
regulator_desc_s2mps11_buck1_4(4),
regulator_desc_s2mps11_buck5,
regulator_desc_s2mps11_buck67810(6, MIN_600_MV, STEP_6_25_MV),
- regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_6_25_MV),
- regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_6_25_MV),
+ regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_12_5_MV),
+ regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_12_5_MV),
regulator_desc_s2mps11_buck9,
regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV),
};
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index dac2f6883e28..80a43074c2f9 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -4023,6 +4023,14 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
usrparm.psf_data &= 0x7fffffffULL;
usrparm.rssd_result &= 0x7fffffffULL;
}
+ /* at least 2 bytes are accessed and should be allocated */
+ if (usrparm.psf_data_len < 2) {
+ DBF_DEV_EVENT(DBF_WARNING, device,
+ "Symmetrix ioctl invalid data length %d",
+ usrparm.psf_data_len);
+ rc = -EINVAL;
+ goto out;
+ }
/* alloc I/O data area */
psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA);
rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 533bd2467910..b40604d0126f 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -2452,11 +2452,12 @@ out:
return rc;
}
-static void qeth_free_qdio_out_buf(struct qeth_qdio_out_q *q)
+static void qeth_free_output_queue(struct qeth_qdio_out_q *q)
{
if (!q)
return;
+ qeth_clear_outq_buffers(q, 1);
qdio_free_buffers(q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q);
kfree(q);
}
@@ -2529,10 +2530,8 @@ out_freeoutqbufs:
card->qdio.out_qs[i]->bufs[j] = NULL;
}
out_freeoutq:
- while (i > 0) {
- qeth_free_qdio_out_buf(card->qdio.out_qs[--i]);
- qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
- }
+ while (i > 0)
+ qeth_free_output_queue(card->qdio.out_qs[--i]);
kfree(card->qdio.out_qs);
card->qdio.out_qs = NULL;
out_freepool:
@@ -2565,10 +2564,8 @@ static void qeth_free_qdio_buffers(struct qeth_card *card)
qeth_free_buffer_pool(card);
/* free outbound qdio_qs */
if (card->qdio.out_qs) {
- for (i = 0; i < card->qdio.no_out_queues; ++i) {
- qeth_clear_outq_buffers(card->qdio.out_qs[i], 1);
- qeth_free_qdio_out_buf(card->qdio.out_qs[i]);
- }
+ for (i = 0; i < card->qdio.no_out_queues; i++)
+ qeth_free_output_queue(card->qdio.out_qs[i]);
kfree(card->qdio.out_qs);
card->qdio.out_qs = NULL;
}
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index 9e685246b98d..5abd37ce4f6f 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -283,6 +283,8 @@ static void virtio_ccw_drop_indicators(struct virtio_ccw_device *vcdev)
{
struct virtio_ccw_vq_info *info;
+ if (!vcdev->airq_info)
+ return;
list_for_each_entry(info, &vcdev->virtqueues, node)
drop_airq_indicator(info->vq, vcdev->airq_info);
}
@@ -423,7 +425,7 @@ static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
if (ret)
return ret;
- return vcdev->config_block->num;
+ return vcdev->config_block->num ?: -ENOENT;
}
static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
diff --git a/drivers/scsi/csiostor/csio_attr.c b/drivers/scsi/csiostor/csio_attr.c
index 2d1c4ebd40f9..6587f20cff1a 100644
--- a/drivers/scsi/csiostor/csio_attr.c
+++ b/drivers/scsi/csiostor/csio_attr.c
@@ -582,12 +582,12 @@ csio_vport_create(struct fc_vport *fc_vport, bool disable)
}
fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING);
+ ln->fc_vport = fc_vport;
if (csio_fcoe_alloc_vnp(hw, ln))
goto error;
*(struct csio_lnode **)fc_vport->dd_data = ln;
- ln->fc_vport = fc_vport;
if (!fc_vport->node_name)
fc_vport->node_name = wwn_to_u64(csio_ln_wwnn(ln));
if (!fc_vport->port_name)
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 77128d680e3b..6f38fa1f468a 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -595,6 +595,13 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
shost->max_lun = ~0;
shost->max_cmd_len = MAX_COMMAND_SIZE;
+ /* turn on DIF support */
+ scsi_host_set_prot(shost,
+ SHOST_DIF_TYPE1_PROTECTION |
+ SHOST_DIF_TYPE2_PROTECTION |
+ SHOST_DIF_TYPE3_PROTECTION);
+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
+
err = scsi_add_host(shost, &pdev->dev);
if (err)
goto err_shost;
@@ -682,13 +689,6 @@ static int isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_host_alloc;
}
pci_info->hosts[i] = h;
-
- /* turn on DIF support */
- scsi_host_set_prot(to_shost(h),
- SHOST_DIF_TYPE1_PROTECTION |
- SHOST_DIF_TYPE2_PROTECTION |
- SHOST_DIF_TYPE3_PROTECTION);
- scsi_host_set_guard(to_shost(h), SHOST_DIX_GUARD_CRC);
}
err = isci_setup_interrupts(pdev);
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index e01a29863c38..867fc036d6ef 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -1739,14 +1739,14 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
fc_frame_payload_op(fp) != ELS_LS_ACC) {
FC_LPORT_DBG(lport, "FLOGI not accepted or bad response\n");
fc_lport_error(lport, fp);
- goto err;
+ goto out;
}
flp = fc_frame_payload_get(fp, sizeof(*flp));
if (!flp) {
FC_LPORT_DBG(lport, "FLOGI bad response\n");
fc_lport_error(lport, fp);
- goto err;
+ goto out;
}
mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1756,7 +1756,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
FC_LPORT_DBG(lport, "FLOGI bad mfs:%hu response, "
"lport->mfs:%hu\n", mfs, lport->mfs);
fc_lport_error(lport, fp);
- goto err;
+ goto out;
}
if (mfs <= lport->mfs) {
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 009a2ef829d6..0fdc8c417035 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1448,7 +1448,13 @@ static int iscsi_xmit_task(struct iscsi_conn *conn)
if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx))
return -ENODATA;
+ spin_lock_bh(&conn->session->back_lock);
+ if (conn->task == NULL) {
+ spin_unlock_bh(&conn->session->back_lock);
+ return -ENODATA;
+ }
__iscsi_get_task(task);
+ spin_unlock_bh(&conn->session->back_lock);
spin_unlock_bh(&conn->session->frwd_lock);
rc = conn->session->tt->xmit_task(task);
spin_lock_bh(&conn->session->frwd_lock);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 12886f96b286..7be581f7c35d 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -818,6 +818,7 @@ static struct domain_device *sas_ex_discover_end_dev(
rphy = sas_end_device_alloc(phy->port);
if (!rphy)
goto out_free;
+ rphy->identify.phy_identifier = phy_id;
child->rphy = rphy;
get_device(&rphy->dev);
@@ -845,6 +846,7 @@ static struct domain_device *sas_ex_discover_end_dev(
child->rphy = rphy;
get_device(&rphy->dev);
+ rphy->identify.phy_identifier = phy_id;
sas_fill_in_rphy(child, rphy);
list_add_tail(&child->disco_list_node, &parent->port->disco_list);
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index d8c03431d0aa..f9f899ec9427 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -7245,6 +7245,8 @@ static int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
fw_ddb_entry);
+ if (rc)
+ goto free_sess;
ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
__func__, fnode_sess->dev.kobj.name);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 707da4ae8185..86a5bae0513b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,7 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.c
* Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -5611,7 +5611,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
lrbp, cmd->request);
}
- clear_bit_unlock(index, &hba->lrb_in_use);
req = cmd->request;
if (req) {
/* Update IO svc time latency histogram */
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 8ef905cbfc9c..9237427728ce 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -692,7 +692,6 @@ static int virtscsi_device_reset(struct scsi_cmnd *sc)
return FAILED;
memset(cmd, 0, sizeof(*cmd));
- cmd->sc = sc;
cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
.type = VIRTIO_SCSI_T_TMF,
.subtype = cpu_to_virtio32(vscsi->vdev,
@@ -751,7 +750,6 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
return FAILED;
memset(cmd, 0, sizeof(*cmd));
- cmd->sc = sc;
cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
.type = VIRTIO_SCSI_T_TMF,
.subtype = VIRTIO_SCSI_T_TMF_ABORT_TASK,
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index fcfb649aedee..830f49eb5ac3 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -301,7 +301,7 @@ enum icnss_driver_state {
ICNSS_FW_DOWN,
ICNSS_DRIVER_UNLOADING,
ICNSS_REJUVENATE,
- ICNSS_DRIVER_LOADING,
+ ICNSS_BLOCK_SHUTDOWN,
};
struct ce_irq_list {
@@ -494,7 +494,7 @@ static struct icnss_priv {
u8 requesting_sub_system;
u16 line_number;
char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
- struct completion driver_probed;
+ struct completion unblock_shutdown;
} *penv;
#ifdef CONFIG_ICNSS_DEBUG
@@ -1182,6 +1182,21 @@ bool icnss_is_fw_ready(void)
}
EXPORT_SYMBOL(icnss_is_fw_ready);
+void icnss_block_shutdown(bool status)
+{
+ if (!penv)
+ return;
+
+ if (status) {
+ set_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state);
+ reinit_completion(&penv->unblock_shutdown);
+ } else {
+ clear_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state);
+ complete(&penv->unblock_shutdown);
+ }
+}
+EXPORT_SYMBOL(icnss_block_shutdown);
+
bool icnss_is_fw_down(void)
{
if (!penv)
@@ -2207,8 +2222,7 @@ static int icnss_call_driver_probe(struct icnss_priv *priv)
icnss_hw_power_on(priv);
- set_bit(ICNSS_DRIVER_LOADING, &priv->state);
- reinit_completion(&penv->driver_probed);
+ icnss_block_shutdown(true);
while (probe_cnt < ICNSS_MAX_PROBE_CNT) {
ret = priv->ops->probe(&priv->pdev->dev);
probe_cnt++;
@@ -2218,13 +2232,11 @@ static int icnss_call_driver_probe(struct icnss_priv *priv)
if (ret < 0) {
icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n",
ret, priv->state, probe_cnt);
- complete(&penv->driver_probed);
- clear_bit(ICNSS_DRIVER_LOADING, &penv->state);
+ icnss_block_shutdown(false);
goto out;
}
- complete(&penv->driver_probed);
- clear_bit(ICNSS_DRIVER_LOADING, &penv->state);
+ icnss_block_shutdown(false);
set_bit(ICNSS_DRIVER_PROBED, &priv->state);
return 0;
@@ -2360,8 +2372,7 @@ static int icnss_driver_event_register_driver(void *data)
if (ret)
goto out;
- set_bit(ICNSS_DRIVER_LOADING, &penv->state);
- reinit_completion(&penv->driver_probed);
+ icnss_block_shutdown(true);
while (probe_cnt < ICNSS_MAX_PROBE_CNT) {
ret = penv->ops->probe(&penv->pdev->dev);
probe_cnt++;
@@ -2371,13 +2382,11 @@ static int icnss_driver_event_register_driver(void *data)
if (ret) {
icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n",
ret, penv->state, probe_cnt);
- clear_bit(ICNSS_DRIVER_LOADING, &penv->state);
- complete(&penv->driver_probed);
+ icnss_block_shutdown(false);
goto power_off;
}
- complete(&penv->driver_probed);
- clear_bit(ICNSS_DRIVER_LOADING, &penv->state);
+ icnss_block_shutdown(false);
set_bit(ICNSS_DRIVER_PROBED, &penv->state);
return 0;
@@ -2601,8 +2610,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
return NOTIFY_OK;
if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed &&
- test_bit(ICNSS_DRIVER_LOADING, &priv->state)) {
- if (!wait_for_completion_timeout(&priv->driver_probed,
+ test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) {
+ if (!wait_for_completion_timeout(&priv->unblock_shutdown,
PROBE_TIMEOUT))
icnss_pr_err("wlan driver probe timeout\n");
}
@@ -4005,8 +4014,8 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_DRIVER_UNLOADING:
seq_puts(s, "DRIVER UNLOADING");
continue;
- case ICNSS_DRIVER_LOADING:
- seq_puts(s, "WLAN DRIVER LOADING");
+ case ICNSS_BLOCK_SHUTDOWN:
+ seq_puts(s, "BLOCK SHUTDOWN");
}
seq_printf(s, "UNKNOWN-%d", i);
@@ -4678,7 +4687,7 @@ static int icnss_probe(struct platform_device *pdev)
penv = priv;
- init_completion(&priv->driver_probed);
+ init_completion(&priv->unblock_shutdown);
icnss_pr_info("Platform driver probed successfully\n");
@@ -4702,7 +4711,7 @@ static int icnss_remove(struct platform_device *pdev)
icnss_debugfs_destroy(penv);
- complete_all(&penv->driver_probed);
+ complete_all(&penv->unblock_shutdown);
icnss_modem_ssr_unregister_notifier(penv);
diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c
index f01ab2499a75..0a49a322c9da 100644
--- a/drivers/soc/qcom/qdsp6v2/voice_svc.c
+++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -68,8 +68,9 @@ static void *dummy_q6_mvm;
static void *dummy_q6_cvs;
dev_t device_num;
+static struct mutex session_lock;
static spinlock_t voicesvc_lock;
-static bool is_released;
+static bool is_released = 1;
static int voice_svc_dummy_reg(void);
static int voice_svc_dummy_dereg(void);
@@ -645,14 +646,23 @@ static int voice_svc_dummy_dereg(void)
static int voice_svc_open(struct inode *inode, struct file *file)
{
struct voice_svc_prvt *prtd = NULL;
+ int ret = 0;
pr_debug("%s\n", __func__);
+ mutex_lock(&session_lock);
+ if (is_released == 0) {
+ pr_err("%s: Access denied to device\n", __func__);
+ ret = -EBUSY;
+ goto done;
+ }
+
prtd = kmalloc(sizeof(struct voice_svc_prvt), GFP_KERNEL);
if (prtd == NULL) {
pr_err("%s: kmalloc failed\n", __func__);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto done;
}
memset(prtd, 0, sizeof(struct voice_svc_prvt));
@@ -676,7 +686,9 @@ static int voice_svc_open(struct inode *inode, struct file *file)
voice_svc_dummy_reg();
reg_dummy_sess = 1;
}
- return 0;
+done:
+ mutex_unlock(&session_lock);
+ return ret;
}
static int voice_svc_release(struct inode *inode, struct file *file)
@@ -810,6 +822,7 @@ static int voice_svc_probe(struct platform_device *pdev)
}
pr_debug("%s: Device created\n", __func__);
spin_lock_init(&voicesvc_lock);
+ mutex_init(&session_lock);
goto done;
add_err:
@@ -832,6 +845,7 @@ static int voice_svc_remove(struct platform_device *pdev)
kfree(voice_svc_dev->cdev);
device_destroy(voice_svc_class, device_num);
class_destroy(voice_svc_class);
+ mutex_destroy(&session_lock);
unregister_chrdev_region(0, MINOR_NUMBER);
return 0;
diff --git a/drivers/soc/qcom/subsystem_notif_virt.c b/drivers/soc/qcom/subsystem_notif_virt.c
index cfeebed0a006..2adbf1d5deb1 100644
--- a/drivers/soc/qcom/subsystem_notif_virt.c
+++ b/drivers/soc/qcom/subsystem_notif_virt.c
@@ -77,17 +77,36 @@ static struct workqueue_struct *ssr_wq;
#ifdef CONFIG_GHS_VMM
+enum subsys_payload_type {
+ SUBSYS_CHANNEL_SEND = 100,
+ SUBSYS_CHANNEL_RECV,
+ SUBSYS_CHANNEL_SEND_ACK,
+ SUBSYS_CHANNEL_RECV_ACK
+};
+
struct ghs_vdev {
void *read_data; /* buffer to receive from gipc */
size_t read_size;
int read_offset;
GIPC_Endpoint endpoint;
spinlock_t io_lock;
+ wait_queue_head_t rx_queue;
+ int xfer_state;
char name[32];
};
static char dt_gipc_path_name[SSR_VIRT_DT_PATHLEN];
+static int ssrvirt_channel_ack(struct ghs_vdev *dev)
+{
+ int ret = 0;
+
+ ret = wait_event_interruptible(dev->rx_queue, ((dev->read_size != 0) ||
+ (dev->xfer_state == SUBSYS_CHANNEL_SEND_ACK)));
+
+ return ret;
+}
+
static int ssrvirt_channel_send(struct ghs_vdev *dev, void *payload,
size_t size)
{
@@ -109,6 +128,8 @@ static int ssrvirt_channel_send(struct ghs_vdev *dev, void *payload,
return -ENOMEM;
}
+ dev->xfer_state = SUBSYS_CHANNEL_SEND;
+
if (size)
memcpy(msg, payload, size);
@@ -122,6 +143,8 @@ static int ssrvirt_channel_send(struct ghs_vdev *dev, void *payload,
return -EAGAIN;
}
+ ssrvirt_channel_ack(dev);
+
return 0;
}
@@ -171,6 +194,14 @@ static void ssrvirt_channel_rx_dispatch(struct subsystem_descriptor *subsystem,
subsystem_handle =
subsys_notif_add_subsys(
subsystem->name);
+
+ if (state == SUBSYS_CHANNEL_SEND_ACK) {
+ dev->xfer_state =
+ SUBSYS_CHANNEL_SEND_ACK;
+ wake_up_interruptible(&dev->rx_queue);
+ continue;
+ }
+
subsys_notif_queue_notification(
subsystem_handle, state, NULL);
}
@@ -209,6 +240,7 @@ static int ssrvirt_commdev_alloc(void *dev_id, const char *name)
memset(dev, 0, sizeof(*dev));
spin_lock_init(&dev->io_lock);
+ init_waitqueue_head(&dev->rx_queue);
gvh_dn = of_find_node_by_path("/aliases");
if (gvh_dn) {
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index ecfe73302350..46a24b4ead09 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -2621,8 +2621,8 @@ ksocknal_enumerate_interfaces(ksock_net_t *net)
net->ksnn_interfaces[j].ksni_ipaddr = ip;
net->ksnn_interfaces[j].ksni_netmask = mask;
- strncpy(&net->ksnn_interfaces[j].ksni_name[0],
- names[i], IFNAMSIZ);
+ strlcpy(net->ksnn_interfaces[j].ksni_name,
+ names[i], sizeof(net->ksnn_interfaces[j].ksni_name));
j++;
}
@@ -2805,8 +2805,9 @@ ksocknal_startup(lnet_ni_t *ni)
goto fail_1;
}
- strncpy(&net->ksnn_interfaces[i].ksni_name[0],
- ni->ni_interfaces[i], IFNAMSIZ);
+ strlcpy(net->ksnn_interfaces[i].ksni_name,
+ ni->ni_interfaces[i],
+ sizeof(net->ksnn_interfaces[i].ksni_name));
}
net->ksnn_ninterfaces = i;
}
diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c
index 1b3bc8386524..75f120da0a84 100644
--- a/drivers/staging/lustre/lnet/lnet/config.c
+++ b/drivers/staging/lustre/lnet/lnet/config.c
@@ -650,8 +650,8 @@ lnet_parse_route(char *str, int *im_a_router)
INIT_LIST_HEAD(&nets);
/* save a copy of the string for error messages */
- strncpy(cmd, str, sizeof(cmd) - 1);
- cmd[sizeof(cmd) - 1] = 0;
+ strncpy(cmd, str, sizeof(cmd));
+ cmd[sizeof(cmd) - 1] = '\0';
sep = str;
for (;;) {
@@ -972,11 +972,13 @@ lnet_splitnets(char *source, struct list_head *nets)
return 0;
offset += (int)(sep - tb->ltb_text);
- tb2 = lnet_new_text_buf(strlen(sep));
+ len = strlen(sep);
+ tb2 = lnet_new_text_buf(len);
if (tb2 == NULL)
return -ENOMEM;
- strcpy(tb2->ltb_text, sep);
+ strncpy(tb2->ltb_text, sep, len);
+ tb2->ltb_text[len] = '\0';
list_add_tail(&tb2->ltb_list, nets);
tb = tb2;
@@ -1021,8 +1023,8 @@ lnet_match_networks(char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
tb = list_entry(raw_entries.next, struct lnet_text_buf_t,
ltb_list);
- strncpy(source, tb->ltb_text, sizeof(source)-1);
- source[sizeof(source)-1] = 0;
+ strncpy(source, tb->ltb_text, sizeof(source));
+ source[sizeof(source)-1] = '\0';
/* replace ltb_text with the network(s) add on match */
rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 64a0335934f3..1066c70434b1 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -612,8 +612,8 @@ lstcon_sesrpc_prep(lstcon_node_t *nd, int transop,
msrq = &(*crpc)->crp_rpc->crpc_reqstmsg.msg_body.mksn_reqst;
msrq->mksn_sid = console_session.ses_id;
msrq->mksn_force = console_session.ses_force;
- strncpy(msrq->mksn_name, console_session.ses_name,
- strlen(console_session.ses_name));
+ strlcpy(msrq->mksn_name, console_session.ses_name,
+ sizeof(msrq->mksn_name));
break;
case LST_TRANS_SESEND:
diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c
index d315dd44ae3b..ed1bc6ac79dd 100644
--- a/drivers/staging/lustre/lnet/selftest/console.c
+++ b/drivers/staging/lustre/lnet/selftest/console.c
@@ -1739,7 +1739,8 @@ lstcon_session_new(char *name, int key, unsigned feats,
console_session.ses_feats_updated = 0;
console_session.ses_timeout = (timeout <= 0) ?
LST_CONSOLE_TIMEOUT : timeout;
- strcpy(console_session.ses_name, name);
+ strlcpy(console_session.ses_name, name,
+ sizeof(console_session.ses_name));
rc = lstcon_batch_add(LST_DEFAULT_BATCH);
if (rc != 0)
@@ -1959,7 +1960,8 @@ lstcon_acceptor_handle(srpc_server_rpc_t *rpc)
if (grp->grp_userland == 0)
grp->grp_userland = 1;
- strcpy(jrep->join_session, console_session.ses_name);
+ strlcpy(jrep->join_session, console_session.ses_name,
+ sizeof(jrep->join_session));
jrep->join_timeout = console_session.ses_timeout;
jrep->join_status = 0;
diff --git a/drivers/staging/lustre/lustre/include/lustre_disk.h b/drivers/staging/lustre/lustre/include/lustre_disk.h
index 5e1ac129a681..7c6933ffc9c1 100644
--- a/drivers/staging/lustre/lustre/include/lustre_disk.h
+++ b/drivers/staging/lustre/lustre/include/lustre_disk.h
@@ -68,6 +68,7 @@
everything as string options */
#define LMD_MAGIC 0xbdacbd03
+#define LMD_PARAMS_MAXLEN 4096
/* gleaned from the mount command - no persistent info here */
struct lustre_mount_data {
diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c
index 1d1c67164418..170775bc7bc0 100644
--- a/drivers/staging/lustre/lustre/libcfs/debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/debug.c
@@ -512,9 +512,9 @@ int libcfs_debug_init(unsigned long bufsize)
}
if (libcfs_debug_file_path != NULL) {
- strncpy(libcfs_debug_file_path_arr,
- libcfs_debug_file_path, PATH_MAX-1);
- libcfs_debug_file_path_arr[PATH_MAX - 1] = '\0';
+ strlcpy(libcfs_debug_file_path_arr,
+ libcfs_debug_file_path,
+ sizeof(libcfs_debug_file_path_arr));
}
/* If libcfs_debug_mb is set to an invalid value or uninitialized
diff --git a/drivers/staging/lustre/lustre/libcfs/hash.c b/drivers/staging/lustre/lustre/libcfs/hash.c
index 030874428952..55fc2190a5bb 100644
--- a/drivers/staging/lustre/lustre/libcfs/hash.c
+++ b/drivers/staging/lustre/lustre/libcfs/hash.c
@@ -1062,8 +1062,7 @@ cfs_hash_create(char *name, unsigned cur_bits, unsigned max_bits,
if (hs == NULL)
return NULL;
- strncpy(hs->hs_name, name, len);
- hs->hs_name[len - 1] = '\0';
+ strlcpy(hs->hs_name, name, len);
hs->hs_flags = flags;
atomic_set(&hs->hs_refcount, 1);
diff --git a/drivers/staging/lustre/lustre/libcfs/workitem.c b/drivers/staging/lustre/lustre/libcfs/workitem.c
index e1143a566ac4..f6cc434af756 100644
--- a/drivers/staging/lustre/lustre/libcfs/workitem.c
+++ b/drivers/staging/lustre/lustre/libcfs/workitem.c
@@ -360,8 +360,8 @@ cfs_wi_sched_create(char *name, struct cfs_cpt_table *cptab,
if (sched == NULL)
return -ENOMEM;
- strncpy(sched->ws_name, name, CFS_WS_NAME_LEN);
- sched->ws_name[CFS_WS_NAME_LEN - 1] = '\0';
+ strlcpy(sched->ws_name, name, CFS_WS_NAME_LEN);
+
sched->ws_cptab = cptab;
sched->ws_cpt = cpt;
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index 5c9502b5b358..951259a98323 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -641,7 +641,7 @@ static int ll_send_mgc_param(struct obd_export *mgc, char *string)
if (!msp)
return -ENOMEM;
- strncpy(msp->mgs_param, string, MGS_PARAM_MAXLEN);
+ strlcpy(msp->mgs_param, string, sizeof(msp->mgs_param));
rc = obd_set_info_async(NULL, mgc, sizeof(KEY_SET_INFO), KEY_SET_INFO,
sizeof(struct mgs_send_param), msp, NULL);
if (rc)
diff --git a/drivers/staging/lustre/lustre/lov/lov_pool.c b/drivers/staging/lustre/lustre/lov/lov_pool.c
index b03827ef6514..b43ce6cd64c2 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pool.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pool.c
@@ -412,8 +412,7 @@ int lov_pool_new(struct obd_device *obd, char *poolname)
if (!new_pool)
return -ENOMEM;
- strncpy(new_pool->pool_name, poolname, LOV_MAXPOOLNAME);
- new_pool->pool_name[LOV_MAXPOOLNAME] = '\0';
+ strlcpy(new_pool->pool_name, poolname, sizeof(new_pool->pool_name));
new_pool->pool_lobd = obd;
/* ref count init to 1 because when created a pool is always used
* up to deletion
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
index 48003d5325e3..7617c57d16e0 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -892,7 +892,7 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
}
lmd->lmd_magic = LMD_MAGIC;
- lmd->lmd_params = kzalloc(4096, GFP_NOFS);
+ lmd->lmd_params = kzalloc(LMD_PARAMS_MAXLEN, GFP_NOFS);
if (!lmd->lmd_params)
return -ENOMEM;
lmd->lmd_params[0] = '\0';
@@ -978,7 +978,7 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
goto invalid;
clear++;
} else if (strncmp(s1, "param=", 6) == 0) {
- int length;
+ size_t length, params_length;
char *tail = strchr(s1 + 6, ',');
if (tail == NULL)
@@ -986,8 +986,12 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)
else
length = tail - s1;
length -= 6;
+ params_length = strlen(lmd->lmd_params);
+ if (params_length + length + 1 >= LMD_PARAMS_MAXLEN)
+ return -E2BIG;
strncat(lmd->lmd_params, s1 + 6, length);
- strcat(lmd->lmd_params, " ");
+ lmd->lmd_params[params_length + length] = '\0';
+ strlcat(lmd->lmd_params, " ", LMD_PARAMS_MAXLEN);
clear++;
} else if (strncmp(s1, "osd=", 4) == 0) {
rc = lmd_parse_string(&lmd->lmd_osd_type, s1 + 4);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index ce036a1ac466..ac87aa12bd7e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -422,6 +422,7 @@ static int ptlrpcd(void *arg)
complete(&pc->pc_starting);
/*
+
* This mainloop strongly resembles ptlrpc_set_wait() except that our
* set never completes. ptlrpcd_check() calls ptlrpc_check_set() when
* there are requests in the set. New requests come in on the set's
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
index 7ff948fe1424..7a206705865b 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
@@ -83,8 +83,7 @@ int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr)
return 0;
}
- strncpy(buf, str, sizeof(buf));
- buf[sizeof(buf) - 1] = '\0';
+ strlcpy(buf, str, sizeof(buf));
bulk = strchr(buf, '-');
if (bulk)
diff --git a/drivers/staging/rdma/hfi1/ud.c b/drivers/staging/rdma/hfi1/ud.c
index 5a9c784bec04..a88e37444be0 100644
--- a/drivers/staging/rdma/hfi1/ud.c
+++ b/drivers/staging/rdma/hfi1/ud.c
@@ -793,7 +793,6 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
wc.ex.imm_data = ohdr->u.ud.imm_data;
wc.wc_flags = IB_WC_WITH_IMM;
- tlen -= sizeof(u32);
} else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
wc.ex.imm_data = 0;
wc.wc_flags = 0;
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 58fe27705b96..cbb4414edd71 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -4232,9 +4232,9 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
struct se_cmd *se_cmd = &cmd->se_cmd;
if (se_cmd->se_tfo != NULL) {
- spin_lock(&se_cmd->t_state_lock);
+ spin_lock_irq(&se_cmd->t_state_lock);
se_cmd->transport_state |= CMD_T_FABRIC_STOP;
- spin_unlock(&se_cmd->t_state_lock);
+ spin_unlock_irq(&se_cmd->t_state_lock);
}
}
spin_unlock_bh(&conn->cmd_lock);
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c
index ccc0ad02d066..7f374ab5b176 100644
--- a/drivers/thermal/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c
@@ -363,7 +363,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev,
proc_priv->soc_dts = intel_soc_dts_iosf_init(
INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0);
- if (proc_priv->soc_dts && pdev->irq) {
+ if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) {
ret = pci_enable_msi(pdev);
if (!ret) {
ret = request_threaded_irq(pdev->irq, NULL,
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 746c76b358a0..b032add92722 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -2326,6 +2326,111 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.setup = pci_default_setup,
.exit = pci_plx9050_exit,
},
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_ACCESIO,
+ .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_pericom_setup,
+ },
/*
* SBS Technologies, Inc., PMC-OCTALPRO 232
*/
@@ -5176,10 +5281,10 @@ static struct pci_device_id serial_pci_tbl[] = {
*/
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7954 },
@@ -5188,10 +5293,10 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7954 },
@@ -5200,10 +5305,10 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7954 },
@@ -5212,13 +5317,13 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7951 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7954 },
@@ -5227,16 +5332,16 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7954 },
@@ -5245,13 +5350,13 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7954 },
+ pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7958 },
+ pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7958 },
+ pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7958 },
@@ -5260,19 +5365,19 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_pericom_PI7C9X7958 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7958 },
+ pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7958 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7958 },
+ pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_pericom_PI7C9X7958 },
{ PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_pericom_PI7C9X7958 },
+ pbn_pericom_PI7C9X7954 },
/*
* Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
*/
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 8b5ec9386f0f..1544a7cc76ff 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1409,7 +1409,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
}
/* ask the core to calculate the divisor */
- baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+ baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 4);
spin_lock_irqsave(&sport->port.lock, flags);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f25af85bb6a1..7e7535873bef 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2112,6 +2112,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
/* begin to receive SETUP packets */
dwc->ep0state = EP0_SETUP_PHASE;
+ dwc->link_state = DWC3_LINK_STATE_SS_DIS;
dwc3_ep0_out_start(dwc);
dwc3_gadget_enable_irq(dwc);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index f97193011bed..fd2150a8db2e 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -988,13 +988,14 @@ retry:
* still busy.
*/
if (!(io_data->read && ep->is_busy)) {
- ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
ep->is_busy = true;
+ ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
}
spin_unlock_irq(&epfile->ffs->eps_lock);
if (unlikely(ret < 0)) {
+ ep->is_busy = false;
ret = -EIO;
} else if (unlikely(
wait_for_completion_interruptible(done))) {
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 68730e7e8557..77681c43318d 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -847,7 +847,7 @@ static struct usb_function *source_sink_alloc_func(
ss = kzalloc(sizeof(*ss), GFP_KERNEL);
if (!ss)
- return NULL;
+ return ERR_PTR(-ENOMEM);
ss_opts = container_of(fi, struct f_ss_opts, func_inst);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 97382301c393..b317594a6342 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -57,6 +57,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
{ USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
+ { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */
{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 3e5b189a79b4..4287e2b1c175 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1020,6 +1020,8 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) },
{ USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) },
{ USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) },
+ /* EZPrototypes devices */
+ { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 76a10b222ff9..ddf5ab983dc9 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -1308,6 +1308,12 @@
#define IONICS_PLUGCOMPUTER_PID 0x0102
/*
+ * EZPrototypes (PID reseller)
+ */
+#define EZPROTOTYPES_VID 0x1c40
+#define HJELMSLUND_USB485_ISO_PID 0x0477
+
+/*
* Dresden Elektronik Sensor Terminal Board
*/
#define DE_VID 0x1cf1 /* Vendor ID */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 7bc2c9fef605..b2b7c12e5c86 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1147,6 +1147,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
.driver_info = NCTRL(0) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */
+ .driver_info = NCTRL(0) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),