Merge 4.19.324 into android-4.19-stable
Changes in 4.19.324
arm64: dts: rockchip: Fix rt5651 compatible value on rk3399-sapphire-excavator
ARM: dts: rockchip: fix rk3036 acodec node
ARM: dts: rockchip: drop grf reference from rk3036 hdmi
ARM: dts: rockchip: Fix the realtek audio codec on rk3036-kylin
HID: core: zero-initialize the report buffer
security/keys: fix slab-out-of-bounds in key_task_permission
sctp: properly validate chunk size in sctp_sf_ootb()
can: c_can: fix {rx,tx}_errors statistics
net: hns3: fix kernel crash when uninstalling driver
media: stb0899_algo: initialize cfr before using it
media: dvbdev: prevent the risk of out of memory access
media: dvb_frontend: don't play tricks with underflow values
media: adv7604: prevent underflow condition when reporting colorspace
ALSA: firewire-lib: fix return value on fail in amdtp_tscm_init()
media: s5p-jpeg: prevent buffer overflows
media: cx24116: prevent overflows on SNR calculus
media: v4l2-tpg: prevent the risk of a division by zero
drm/amdgpu: add missing size check in amdgpu_debugfs_gprwave_read()
drm/amdgpu: prevent NULL pointer dereference if ATIF is not supported
dm cache: correct the number of origin blocks to match the target length
dm cache: fix out-of-bounds access to the dirty bitset when resizing
dm cache: optimize dirty bit checking with find_next_bit when resizing
dm cache: fix potential out-of-bounds access on the first resume
dm-unstriped: cast an operand to sector_t to prevent potential uint32_t overflow
nfs: Fix KMSAN warning in decode_getfattr_attrs()
btrfs: reinitialize delayed ref list after deleting it from the list
bonding (gcc13): synchronize bond_{a,t}lb_xmit() types
net: bridge: xmit: make sure we have at least eth header len bytes
media: uvcvideo: Skip parsing frames of type UVC_VS_UNDEFINED in uvc_parse_format
fs/proc: fix compile warning about variable 'vmcore_mmap_ops'
usb: musb: sunxi: Fix accessing an released usb phy
USB: serial: io_edgeport: fix use after free in debug printk
USB: serial: qcserial: add support for Sierra Wireless EM86xx
USB: serial: option: add Fibocom FG132 0x0112 composition
USB: serial: option: add Quectel RG650V
irqchip/gic-v3: Force propagation of the active state with a read-back
ocfs2: remove entry once instead of null-ptr-dereference in ocfs2_xa_remove()
ALSA: pcm: Return 0 when size < start_threshold in capture
ALSA: usb-audio: Add custom mixer status quirks for RME CC devices
ALSA: usb-audio: Support jack detection on Dell dock
ALSA: usb-audio: Add quirks for Dell WD19 dock
hv_sock: Initializing vsk->trans to NULL to prevent a dangling pointer
vsock/virtio: Initialization of the dangling pointer occurring in vsk->trans
ALSA: usb-audio: Add endianness annotations
9p: Avoid creating multiple slab caches with the same name
HID: multitouch: Add quirk for HONOR MagicBook Art 14 touchpad
bpf: use kvzmalloc to allocate BPF verifier environment
sound: Make CONFIG_SND depend on INDIRECT_IOMEM instead of UML
powerpc/powernv: Free name on error in opal_event_init()
fs: Fix uninitialized value issue in from_kuid and from_kgid
net: usb: qmi_wwan: add Fibocom FG132 0x0112 composition
9p: fix slab cache name creation for real
Linux 4.19.324
Change-Id: Ib8e7c89304d2c2cc72aea03446ea40a8704b41ec
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 19
|
||||
SUBLEVEL = 323
|
||||
SUBLEVEL = 324
|
||||
EXTRAVERSION =
|
||||
NAME = "People's Front"
|
||||
|
||||
|
||||
@@ -300,8 +300,8 @@
|
||||
&i2c2 {
|
||||
status = "okay";
|
||||
|
||||
rt5616: rt5616@1b {
|
||||
compatible = "rt5616";
|
||||
rt5616: audio-codec@1b {
|
||||
compatible = "realtek,rt5616";
|
||||
reg = <0x1b>;
|
||||
clocks = <&cru SCLK_I2S_OUT>;
|
||||
clock-names = "mclk";
|
||||
|
||||
@@ -316,12 +316,13 @@
|
||||
};
|
||||
};
|
||||
|
||||
acodec: acodec-ana@20030000 {
|
||||
compatible = "rk3036-codec";
|
||||
acodec: audio-codec@20030000 {
|
||||
compatible = "rockchip,rk3036-codec";
|
||||
reg = <0x20030000 0x4000>;
|
||||
rockchip,grf = <&grf>;
|
||||
clock-names = "acodec_pclk";
|
||||
clocks = <&cru PCLK_ACODEC>;
|
||||
rockchip,grf = <&grf>;
|
||||
#sound-dai-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -331,7 +332,6 @@
|
||||
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru PCLK_HDMI>;
|
||||
clock-names = "pclk";
|
||||
rockchip,grf = <&grf>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&hdmi_ctl>;
|
||||
status = "disabled";
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
status = "okay";
|
||||
|
||||
rt5651: rt5651@1a {
|
||||
compatible = "rockchip,rt5651";
|
||||
compatible = "realtek,rt5651";
|
||||
reg = <0x1a>;
|
||||
clocks = <&cru SCLK_I2S_8CH_OUT>;
|
||||
clock-names = "mclk";
|
||||
|
||||
@@ -289,6 +289,7 @@ int __init opal_event_init(void)
|
||||
name, NULL);
|
||||
if (rc) {
|
||||
pr_warn("Error %d requesting OPAL irq %d\n", rc, (int)r->start);
|
||||
kfree(name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +115,8 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
|
||||
&buffer);
|
||||
obj = (union acpi_object *)buffer.pointer;
|
||||
|
||||
/* Fail if calling the method fails and ATIF is supported */
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
/* Fail if calling the method fails */
|
||||
if (ACPI_FAILURE(status)) {
|
||||
DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
|
||||
acpi_format_exception(status));
|
||||
kfree(obj);
|
||||
|
||||
@@ -394,7 +394,7 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf,
|
||||
if (!adev->smc_rreg)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (size & 0x3 || *pos & 0x3)
|
||||
if (size > 4096 || size & 0x3 || *pos & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
while (size) {
|
||||
|
||||
@@ -1482,7 +1482,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
|
||||
|
||||
u32 len = hid_report_len(report) + 7;
|
||||
|
||||
return kmalloc(len, flags);
|
||||
return kzalloc(len, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
|
||||
|
||||
|
||||
@@ -1986,6 +1986,11 @@ static const struct hid_device_id mt_devices[] = {
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
0x347d, 0x7853) },
|
||||
|
||||
/* HONOR MagicBook Art 14 touchpad */
|
||||
{ .driver_data = MT_CLS_VTL,
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
0x35cc, 0x0104) },
|
||||
|
||||
/* Ilitek dual touch panel */
|
||||
{ .driver_data = MT_CLS_NSMU,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
|
||||
|
||||
@@ -254,6 +254,13 @@ static int gic_irq_set_irqchip_state(struct irq_data *d,
|
||||
}
|
||||
|
||||
gic_poke_irq(d, reg);
|
||||
|
||||
/*
|
||||
* Force read-back to guarantee that the active state has taken
|
||||
* effect, and won't race with a guest-driven deactivation.
|
||||
*/
|
||||
if (reg == GICD_ISACTIVER)
|
||||
gic_peek_irq(d, reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2080,7 +2080,6 @@ struct cache_args {
|
||||
sector_t cache_sectors;
|
||||
|
||||
struct dm_dev *origin_dev;
|
||||
sector_t origin_sectors;
|
||||
|
||||
uint32_t block_size;
|
||||
|
||||
@@ -2162,6 +2161,7 @@ static int parse_cache_dev(struct cache_args *ca, struct dm_arg_set *as,
|
||||
static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as,
|
||||
char **error)
|
||||
{
|
||||
sector_t origin_sectors;
|
||||
int r;
|
||||
|
||||
if (!at_least_one_arg(as, error))
|
||||
@@ -2174,8 +2174,8 @@ static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as,
|
||||
return r;
|
||||
}
|
||||
|
||||
ca->origin_sectors = get_dev_size(ca->origin_dev);
|
||||
if (ca->ti->len > ca->origin_sectors) {
|
||||
origin_sectors = get_dev_size(ca->origin_dev);
|
||||
if (ca->ti->len > origin_sectors) {
|
||||
*error = "Device size larger than cached device";
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2498,7 +2498,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
|
||||
|
||||
ca->metadata_dev = ca->origin_dev = ca->cache_dev = NULL;
|
||||
|
||||
origin_blocks = cache->origin_sectors = ca->origin_sectors;
|
||||
origin_blocks = cache->origin_sectors = ti->len;
|
||||
origin_blocks = block_div(origin_blocks, ca->block_size);
|
||||
cache->origin_blocks = to_oblock(origin_blocks);
|
||||
|
||||
@@ -2991,19 +2991,19 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache)
|
||||
static bool can_resize(struct cache *cache, dm_cblock_t new_size)
|
||||
{
|
||||
if (from_cblock(new_size) > from_cblock(cache->cache_size)) {
|
||||
if (cache->sized) {
|
||||
DMERR("%s: unable to extend cache due to missing cache table reload",
|
||||
cache_device_name(cache));
|
||||
return false;
|
||||
}
|
||||
DMERR("%s: unable to extend cache due to missing cache table reload",
|
||||
cache_device_name(cache));
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't drop a dirty block when shrinking the cache.
|
||||
*/
|
||||
while (from_cblock(new_size) < from_cblock(cache->cache_size)) {
|
||||
new_size = to_cblock(from_cblock(new_size) + 1);
|
||||
if (is_dirty(cache, new_size)) {
|
||||
if (cache->loaded_mappings) {
|
||||
new_size = to_cblock(find_next_bit(cache->dirty_bitset,
|
||||
from_cblock(cache->cache_size),
|
||||
from_cblock(new_size)));
|
||||
if (new_size != cache->cache_size) {
|
||||
DMERR("%s: unable to shrink cache; cache block %llu is dirty",
|
||||
cache_device_name(cache),
|
||||
(unsigned long long) from_cblock(new_size));
|
||||
@@ -3039,20 +3039,15 @@ static int cache_preresume(struct dm_target *ti)
|
||||
/*
|
||||
* Check to see if the cache has resized.
|
||||
*/
|
||||
if (!cache->sized) {
|
||||
r = resize_cache_dev(cache, csize);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
cache->sized = true;
|
||||
|
||||
} else if (csize != cache->cache_size) {
|
||||
if (!cache->sized || csize != cache->cache_size) {
|
||||
if (!can_resize(cache, csize))
|
||||
return -EINVAL;
|
||||
|
||||
r = resize_cache_dev(cache, csize);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
cache->sized = true;
|
||||
}
|
||||
|
||||
if (!cache->loaded_mappings) {
|
||||
|
||||
@@ -84,8 +84,8 @@ static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
}
|
||||
uc->physical_start = start;
|
||||
|
||||
uc->unstripe_offset = uc->unstripe * uc->chunk_size;
|
||||
uc->unstripe_width = (uc->stripes - 1) * uc->chunk_size;
|
||||
uc->unstripe_offset = (sector_t)uc->unstripe * uc->chunk_size;
|
||||
uc->unstripe_width = (sector_t)(uc->stripes - 1) * uc->chunk_size;
|
||||
uc->chunk_shift = is_power_of_2(uc->chunk_size) ? fls(uc->chunk_size) - 1 : 0;
|
||||
|
||||
tmp_len = ti->len;
|
||||
|
||||
@@ -1639,6 +1639,9 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
|
||||
unsigned p;
|
||||
unsigned x;
|
||||
|
||||
if (WARN_ON_ONCE(!tpg->src_width || !tpg->scaled_width))
|
||||
return;
|
||||
|
||||
switch (tpg->pattern) {
|
||||
case TPG_PAT_GREEN:
|
||||
contrast = TPG_COLOR_100_RED;
|
||||
|
||||
@@ -454,8 +454,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
|
||||
|
||||
default:
|
||||
fepriv->auto_step++;
|
||||
fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
|
||||
break;
|
||||
fepriv->auto_sub_step = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ready) fepriv->auto_sub_step++;
|
||||
|
||||
@@ -96,10 +96,15 @@ static DECLARE_RWSEM(minor_rwsem);
|
||||
static int dvb_device_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
unsigned int minor = iminor(inode);
|
||||
|
||||
if (minor >= MAX_DVB_MINORS)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&dvbdev_mutex);
|
||||
down_read(&minor_rwsem);
|
||||
dvbdev = dvb_minors[iminor(inode)];
|
||||
|
||||
dvbdev = dvb_minors[minor];
|
||||
|
||||
if (dvbdev && dvbdev->fops) {
|
||||
int err = 0;
|
||||
@@ -539,7 +544,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
|
||||
if (dvb_minors[minor] == NULL)
|
||||
break;
|
||||
if (minor == MAX_DVB_MINORS) {
|
||||
if (minor >= MAX_DVB_MINORS) {
|
||||
if (new_node) {
|
||||
list_del (&new_node->list_head);
|
||||
kfree(dvbdevfops);
|
||||
@@ -554,6 +559,14 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
}
|
||||
#else
|
||||
minor = nums2minor(adap->num, type, id);
|
||||
if (minor >= MAX_DVB_MINORS) {
|
||||
dvb_media_device_free(dvbdev);
|
||||
list_del(&dvbdev->list_head);
|
||||
kfree(dvbdev);
|
||||
*pdvbdev = NULL;
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
dvbdev->minor = minor;
|
||||
dvb_minors[minor] = dvb_device_get(dvbdev);
|
||||
|
||||
@@ -753,6 +753,7 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct cx24116_state *state = fe->demodulator_priv;
|
||||
u8 snr_reading;
|
||||
int ret;
|
||||
static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
|
||||
0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
|
||||
0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
|
||||
@@ -761,7 +762,11 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
|
||||
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
|
||||
ret = cx24116_readreg(state, CX24116_REG_QUALITY0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
snr_reading = ret;
|
||||
|
||||
if (snr_reading >= 0xa0 /* 100% */)
|
||||
*snr = 0xffff;
|
||||
|
||||
@@ -281,7 +281,7 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
|
||||
|
||||
short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
|
||||
int index = 0;
|
||||
u8 cfr[2];
|
||||
u8 cfr[2] = {0};
|
||||
u8 reg;
|
||||
|
||||
internal->status = NOCARRIER;
|
||||
|
||||
@@ -2453,10 +2453,10 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
|
||||
const struct adv76xx_chip_info *info = state->info;
|
||||
struct v4l2_dv_timings timings;
|
||||
struct stdi_readback stdi;
|
||||
u8 reg_io_0x02 = io_read(sd, 0x02);
|
||||
int ret;
|
||||
u8 reg_io_0x02;
|
||||
u8 edid_enabled;
|
||||
u8 cable_det;
|
||||
|
||||
static const char * const csc_coeff_sel_rb[16] = {
|
||||
"bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB",
|
||||
"reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709",
|
||||
@@ -2555,13 +2555,21 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
|
||||
v4l2_info(sd, "-----Color space-----\n");
|
||||
v4l2_info(sd, "RGB quantization range ctrl: %s\n",
|
||||
rgb_quantization_range_txt[state->rgb_quantization_range]);
|
||||
v4l2_info(sd, "Input color space: %s\n",
|
||||
input_color_space_txt[reg_io_0x02 >> 4]);
|
||||
v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",
|
||||
(reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
|
||||
(((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ?
|
||||
"(16-235)" : "(0-255)",
|
||||
(reg_io_0x02 & 0x08) ? "enabled" : "disabled");
|
||||
|
||||
ret = io_read(sd, 0x02);
|
||||
if (ret < 0) {
|
||||
v4l2_info(sd, "Can't read Input/Output color space\n");
|
||||
} else {
|
||||
reg_io_0x02 = ret;
|
||||
|
||||
v4l2_info(sd, "Input color space: %s\n",
|
||||
input_color_space_txt[reg_io_0x02 >> 4]);
|
||||
v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",
|
||||
(reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
|
||||
(((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ?
|
||||
"(16-235)" : "(0-255)",
|
||||
(reg_io_0x02 & 0x08) ? "enabled" : "disabled");
|
||||
}
|
||||
v4l2_info(sd, "Color space conversion: %s\n",
|
||||
csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]);
|
||||
|
||||
|
||||
@@ -803,11 +803,14 @@ static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
|
||||
(unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2;
|
||||
jpeg_buffer.curr = 0;
|
||||
|
||||
word = 0;
|
||||
|
||||
if (get_word_be(&jpeg_buffer, &word))
|
||||
return;
|
||||
jpeg_buffer.size = (long)word - 2;
|
||||
|
||||
if (word < 2)
|
||||
jpeg_buffer.size = 0;
|
||||
else
|
||||
jpeg_buffer.size = (long)word - 2;
|
||||
|
||||
jpeg_buffer.data += 2;
|
||||
jpeg_buffer.curr = 0;
|
||||
|
||||
@@ -1086,6 +1089,7 @@ static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
|
||||
if (byte == -1)
|
||||
return -1;
|
||||
*word = (unsigned int)byte | temp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1173,7 +1177,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
|
||||
if (get_word_be(&jpeg_buffer, &word))
|
||||
break;
|
||||
length = (long)word - 2;
|
||||
if (!length)
|
||||
if (length <= 0)
|
||||
return false;
|
||||
sof = jpeg_buffer.curr; /* after 0xffc0 */
|
||||
sof_len = length;
|
||||
@@ -1204,7 +1208,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
|
||||
if (get_word_be(&jpeg_buffer, &word))
|
||||
break;
|
||||
length = (long)word - 2;
|
||||
if (!length)
|
||||
if (length <= 0)
|
||||
return false;
|
||||
if (n_dqt >= S5P_JPEG_MAX_MARKER)
|
||||
return false;
|
||||
@@ -1217,7 +1221,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
|
||||
if (get_word_be(&jpeg_buffer, &word))
|
||||
break;
|
||||
length = (long)word - 2;
|
||||
if (!length)
|
||||
if (length <= 0)
|
||||
return false;
|
||||
if (n_dht >= S5P_JPEG_MAX_MARKER)
|
||||
return false;
|
||||
@@ -1242,6 +1246,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
|
||||
if (get_word_be(&jpeg_buffer, &word))
|
||||
break;
|
||||
length = (long)word - 2;
|
||||
/* No need to check underflows as skip() does it */
|
||||
skip(&jpeg_buffer, length);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -575,7 +575,7 @@ static int uvc_parse_format(struct uvc_device *dev,
|
||||
/* Parse the frame descriptors. Only uncompressed, MJPEG and frame
|
||||
* based formats have frame descriptors.
|
||||
*/
|
||||
while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
|
||||
while (ftype && buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
|
||||
buffer[2] == ftype) {
|
||||
frame = &format->frame[format->nframes];
|
||||
if (ftype != UVC_VS_FRAME_FRAME_BASED)
|
||||
|
||||
@@ -991,7 +991,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
|
||||
|
||||
/* common for all type of bus errors */
|
||||
priv->can.can_stats.bus_error++;
|
||||
stats->rx_errors++;
|
||||
|
||||
/* propagate the error condition to the CAN stack */
|
||||
skb = alloc_can_err_skb(dev, &cf);
|
||||
@@ -1008,26 +1007,32 @@ static int c_can_handle_bus_err(struct net_device *dev,
|
||||
case LEC_STUFF_ERROR:
|
||||
netdev_dbg(dev, "stuff error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
||||
stats->rx_errors++;
|
||||
break;
|
||||
case LEC_FORM_ERROR:
|
||||
netdev_dbg(dev, "form error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_FORM;
|
||||
stats->rx_errors++;
|
||||
break;
|
||||
case LEC_ACK_ERROR:
|
||||
netdev_dbg(dev, "ack error\n");
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
stats->tx_errors++;
|
||||
break;
|
||||
case LEC_BIT1_ERROR:
|
||||
netdev_dbg(dev, "bit1 error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT1;
|
||||
stats->tx_errors++;
|
||||
break;
|
||||
case LEC_BIT0_ERROR:
|
||||
netdev_dbg(dev, "bit0 error\n");
|
||||
cf->data[2] |= CAN_ERR_PROT_BIT0;
|
||||
stats->tx_errors++;
|
||||
break;
|
||||
case LEC_CRC_ERROR:
|
||||
netdev_dbg(dev, "CRC error\n");
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
stats->rx_errors++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -25,8 +25,11 @@ void hnae3_unregister_ae_algo_prepare(struct hnae3_ae_algo *ae_algo)
|
||||
pci_id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
|
||||
if (!pci_id)
|
||||
continue;
|
||||
if (IS_ENABLED(CONFIG_PCI_IOV))
|
||||
if (IS_ENABLED(CONFIG_PCI_IOV)) {
|
||||
device_lock(&ae_dev->pdev->dev);
|
||||
pci_disable_sriov(ae_dev->pdev);
|
||||
device_unlock(&ae_dev->pdev->dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(hnae3_unregister_ae_algo_prepare);
|
||||
|
||||
@@ -1385,6 +1385,7 @@ static const struct usb_device_id products[] = {
|
||||
{QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */
|
||||
{QMI_QUIRK_SET_DTR(0x2c7c, 0x030e, 4)}, /* Quectel EM05GV2 */
|
||||
{QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */
|
||||
{QMI_QUIRK_SET_DTR(0x2cb7, 0x0112, 0)}, /* Fibocom FG132 */
|
||||
{QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */
|
||||
{QMI_FIXED_INTF(0x0489, 0xe0b5, 0)}, /* Foxconn T77W968 LTE with eSIM support*/
|
||||
{QMI_FIXED_INTF(0x2692, 0x9025, 4)}, /* Cellient MPL200 (rebranded Qualcomm 05c6:9025) */
|
||||
|
||||
@@ -286,8 +286,6 @@ static int sunxi_musb_exit(struct musb *musb)
|
||||
if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
|
||||
sunxi_sram_release(musb->controller->parent);
|
||||
|
||||
devm_usb_put_phy(glue->dev, glue->xceiv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -846,11 +846,12 @@ static void edge_bulk_out_data_callback(struct urb *urb)
|
||||
static void edge_bulk_out_cmd_callback(struct urb *urb)
|
||||
{
|
||||
struct edgeport_port *edge_port = urb->context;
|
||||
struct device *dev = &urb->dev->dev;
|
||||
int status = urb->status;
|
||||
|
||||
atomic_dec(&CmdUrbs);
|
||||
dev_dbg(&urb->dev->dev, "%s - FREE URB %p (outstanding %d)\n",
|
||||
__func__, urb, atomic_read(&CmdUrbs));
|
||||
dev_dbg(dev, "%s - FREE URB %p (outstanding %d)\n", __func__, urb,
|
||||
atomic_read(&CmdUrbs));
|
||||
|
||||
|
||||
/* clean up the transfer buffer */
|
||||
@@ -860,8 +861,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
|
||||
usb_free_urb(urb);
|
||||
|
||||
if (status) {
|
||||
dev_dbg(&urb->dev->dev,
|
||||
"%s - nonzero write bulk status received: %d\n",
|
||||
dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -251,6 +251,7 @@ static void option_instat_callback(struct urb *urb);
|
||||
#define QUECTEL_VENDOR_ID 0x2c7c
|
||||
/* These Quectel products use Quectel's vendor ID */
|
||||
#define QUECTEL_PRODUCT_EC21 0x0121
|
||||
#define QUECTEL_PRODUCT_RG650V 0x0122
|
||||
#define QUECTEL_PRODUCT_EM061K_LTA 0x0123
|
||||
#define QUECTEL_PRODUCT_EM061K_LMS 0x0124
|
||||
#define QUECTEL_PRODUCT_EC25 0x0125
|
||||
@@ -1273,6 +1274,8 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG912Y, 0xff, 0, 0) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG916Q, 0xff, 0x00, 0x00) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0xff, 0x30) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0, 0) },
|
||||
|
||||
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
|
||||
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
|
||||
@@ -2320,6 +2323,9 @@ static const struct usb_device_id option_ids[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0xff, 0x30) }, /* Fibocom FG150 Diag */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0, 0) }, /* Fibocom FG150 AT */
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0111, 0xff) }, /* Fibocom FM160 (MBIM mode) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x0112, 0xff, 0xff, 0x30) }, /* Fibocom FG132 Diag */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x0112, 0xff, 0xff, 0x40) }, /* Fibocom FG132 AT */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x0112, 0xff, 0, 0) }, /* Fibocom FG132 NMEA */
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0115, 0xff), /* Fibocom FM135 (laptop MBIM) */
|
||||
.driver_info = RSVD(5) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
|
||||
|
||||
@@ -166,6 +166,8 @@ static const struct usb_device_id id_table[] = {
|
||||
{DEVICE_SWI(0x1199, 0x9090)}, /* Sierra Wireless EM7565 QDL */
|
||||
{DEVICE_SWI(0x1199, 0x9091)}, /* Sierra Wireless EM7565 */
|
||||
{DEVICE_SWI(0x1199, 0x90d2)}, /* Sierra Wireless EM9191 QDL */
|
||||
{DEVICE_SWI(0x1199, 0x90e4)}, /* Sierra Wireless EM86xx QDL*/
|
||||
{DEVICE_SWI(0x1199, 0x90e5)}, /* Sierra Wireless EM86xx */
|
||||
{DEVICE_SWI(0x1199, 0xc080)}, /* Sierra Wireless EM7590 QDL */
|
||||
{DEVICE_SWI(0x1199, 0xc081)}, /* Sierra Wireless EM7590 */
|
||||
{DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
|
||||
|
||||
@@ -426,7 +426,7 @@ static int insert_delayed_ref(struct btrfs_trans_handle *trans,
|
||||
&href->ref_add_list);
|
||||
else if (ref->action == BTRFS_DROP_DELAYED_REF) {
|
||||
ASSERT(!list_empty(&exist->add_list));
|
||||
list_del(&exist->add_list);
|
||||
list_del_init(&exist->add_list);
|
||||
} else {
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
@@ -1483,6 +1483,7 @@ void nfs_fattr_init(struct nfs_fattr *fattr)
|
||||
fattr->gencount = nfs_inc_attr_generation_counter();
|
||||
fattr->owner_name = NULL;
|
||||
fattr->group_name = NULL;
|
||||
fattr->mdsthreshold = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_fattr_init);
|
||||
|
||||
|
||||
@@ -1143,9 +1143,12 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
trace_ocfs2_setattr(inode, dentry,
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno,
|
||||
dentry->d_name.len, dentry->d_name.name,
|
||||
attr->ia_valid, attr->ia_mode,
|
||||
from_kuid(&init_user_ns, attr->ia_uid),
|
||||
from_kgid(&init_user_ns, attr->ia_gid));
|
||||
attr->ia_valid,
|
||||
attr->ia_valid & ATTR_MODE ? attr->ia_mode : 0,
|
||||
attr->ia_valid & ATTR_UID ?
|
||||
from_kuid(&init_user_ns, attr->ia_uid) : 0,
|
||||
attr->ia_valid & ATTR_GID ?
|
||||
from_kgid(&init_user_ns, attr->ia_gid) : 0);
|
||||
|
||||
/* ensuring we don't even attempt to truncate a symlink */
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
|
||||
@@ -2050,8 +2050,7 @@ static int ocfs2_xa_remove(struct ocfs2_xa_loc *loc,
|
||||
rc = 0;
|
||||
ocfs2_xa_cleanup_value_truncate(loc, "removing",
|
||||
orig_clusters);
|
||||
if (rc)
|
||||
goto out;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -431,10 +431,6 @@ static vm_fault_t mmap_vmcore_fault(struct vm_fault *vmf)
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct vmcore_mmap_ops = {
|
||||
.fault = mmap_vmcore_fault,
|
||||
};
|
||||
|
||||
/**
|
||||
* vmcore_alloc_buf - allocate buffer in vmalloc memory
|
||||
* @sizez: size of buffer
|
||||
@@ -462,6 +458,11 @@ static inline char *vmcore_alloc_buf(size_t size)
|
||||
* virtually contiguous user-space in ELF layout.
|
||||
*/
|
||||
#ifdef CONFIG_MMU
|
||||
|
||||
static const struct vm_operations_struct vmcore_mmap_ops = {
|
||||
.fault = mmap_vmcore_fault,
|
||||
};
|
||||
|
||||
/*
|
||||
* remap_oldmem_pfn_checked - do remap_oldmem_pfn_range replacing all pages
|
||||
* reported as not being ram with the zero page.
|
||||
|
||||
@@ -172,8 +172,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave);
|
||||
void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave);
|
||||
void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link);
|
||||
void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave);
|
||||
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
|
||||
int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
|
||||
netdev_tx_t bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
|
||||
netdev_tx_t bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
|
||||
void bond_alb_monitor(struct work_struct *);
|
||||
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
|
||||
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
|
||||
|
||||
@@ -6446,7 +6446,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
|
||||
/* 'struct bpf_verifier_env' can be global, but since it's not small,
|
||||
* allocate/free it every time bpf_check() is called
|
||||
*/
|
||||
env = kzalloc(sizeof(struct bpf_verifier_env), GFP_KERNEL);
|
||||
env = kvzalloc(sizeof(struct bpf_verifier_env), GFP_KERNEL);
|
||||
if (!env)
|
||||
return -ENOMEM;
|
||||
log = &env->log;
|
||||
@@ -6573,6 +6573,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
|
||||
mutex_unlock(&bpf_verifier_lock);
|
||||
vfree(env->insn_aux_data);
|
||||
err_free_env:
|
||||
kfree(env);
|
||||
kvfree(env);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1016,8 +1016,10 @@ static int p9_client_version(struct p9_client *c)
|
||||
struct p9_client *p9_client_create(const char *dev_name, char *options)
|
||||
{
|
||||
int err;
|
||||
static atomic_t seqno = ATOMIC_INIT(0);
|
||||
struct p9_client *clnt;
|
||||
char *client_id;
|
||||
char *cache_name;
|
||||
|
||||
err = 0;
|
||||
clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
|
||||
@@ -1070,15 +1072,23 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
|
||||
if (err)
|
||||
goto close_trans;
|
||||
|
||||
cache_name = kasprintf(GFP_KERNEL,
|
||||
"9p-fcall-cache-%u", atomic_inc_return(&seqno));
|
||||
if (!cache_name) {
|
||||
err = -ENOMEM;
|
||||
goto close_trans;
|
||||
}
|
||||
|
||||
/* P9_HDRSZ + 4 is the smallest packet header we can have that is
|
||||
* followed by data accessed from userspace by read
|
||||
*/
|
||||
clnt->fcall_cache =
|
||||
kmem_cache_create_usercopy("9p-fcall-cache", clnt->msize,
|
||||
kmem_cache_create_usercopy(cache_name, clnt->msize,
|
||||
0, 0, P9_HDRSZ + 4,
|
||||
clnt->msize - (P9_HDRSZ + 4),
|
||||
NULL);
|
||||
|
||||
kfree(cache_name);
|
||||
return clnt;
|
||||
|
||||
close_trans:
|
||||
|
||||
@@ -41,6 +41,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
const unsigned char *dest;
|
||||
u16 vid = 0;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) {
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
@@ -3652,7 +3652,7 @@ enum sctp_disposition sctp_sf_ootb(struct net *net,
|
||||
}
|
||||
|
||||
ch = (struct sctp_chunkhdr *)ch_end;
|
||||
} while (ch_end < skb_tail_pointer(skb));
|
||||
} while (ch_end + sizeof(*ch) < skb_tail_pointer(skb));
|
||||
|
||||
if (ootb_shut_ack)
|
||||
return sctp_sf_shut_8_4_5(net, ep, asoc, type, arg, commands);
|
||||
|
||||
@@ -510,6 +510,7 @@ static void hvs_destruct(struct vsock_sock *vsk)
|
||||
vmbus_hvsock_device_unregister(chan);
|
||||
|
||||
kfree(hvs);
|
||||
vsk->trans = NULL;
|
||||
}
|
||||
|
||||
static int hvs_dgram_bind(struct vsock_sock *vsk, struct sockaddr_vm *addr)
|
||||
|
||||
@@ -650,6 +650,7 @@ void virtio_transport_destruct(struct vsock_sock *vsk)
|
||||
struct virtio_vsock_sock *vvs = vsk->trans;
|
||||
|
||||
kfree(vvs);
|
||||
vsk->trans = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_transport_destruct);
|
||||
|
||||
|
||||
@@ -739,8 +739,11 @@ static bool search_nested_keyrings(struct key *keyring,
|
||||
for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
||||
ptr = READ_ONCE(node->slots[slot]);
|
||||
|
||||
if (assoc_array_ptr_is_meta(ptr) && node->back_pointer)
|
||||
goto descend_to_node;
|
||||
if (assoc_array_ptr_is_meta(ptr)) {
|
||||
if (node->back_pointer ||
|
||||
assoc_array_ptr_is_shortcut(ptr))
|
||||
goto descend_to_node;
|
||||
}
|
||||
|
||||
if (!keyring_ptr_is_keyring(ptr))
|
||||
continue;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
menuconfig SOUND
|
||||
tristate "Sound card support"
|
||||
depends on HAS_IOMEM || UML
|
||||
depends on HAS_IOMEM || INDIRECT_IOMEM
|
||||
help
|
||||
If you have a sound card in your computer, i.e. if it can say more
|
||||
than an occasional beep, say Y.
|
||||
|
||||
@@ -2181,11 +2181,16 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
|
||||
goto _end_unlock;
|
||||
|
||||
if (!is_playback &&
|
||||
runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
|
||||
size >= runtime->start_threshold) {
|
||||
err = snd_pcm_start(substream);
|
||||
if (err < 0)
|
||||
runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
|
||||
if (size >= runtime->start_threshold) {
|
||||
err = snd_pcm_start(substream);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
} else {
|
||||
/* nothing to do */
|
||||
err = 0;
|
||||
goto _end_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
runtime->twake = runtime->control->avail_min ? : 1;
|
||||
|
||||
@@ -172,7 +172,7 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
|
||||
CIP_NONBLOCKING | CIP_SKIP_DBC_ZERO_CHECK, fmt,
|
||||
process_data_blocks, sizeof(struct amdtp_tscm));
|
||||
if (err < 0)
|
||||
return 0;
|
||||
return err;
|
||||
|
||||
/* Use fixed value for FDF field. */
|
||||
s->fdf = 0x00;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/audio.h>
|
||||
@@ -36,6 +37,7 @@
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/hda_verbs.h>
|
||||
#include <sound/hwdep.h>
|
||||
#include <sound/info.h>
|
||||
#include <sound/tlv.h>
|
||||
@@ -1803,6 +1805,169 @@ static int snd_soundblaster_e1_switch_create(struct usb_mixer_interface *mixer)
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dell WD15 dock jack detection
|
||||
*
|
||||
* The WD15 contains an ALC4020 USB audio controller and ALC3263 audio codec
|
||||
* from Realtek. It is a UAC 1 device, and UAC 1 does not support jack
|
||||
* detection. Instead, jack detection works by sending HD Audio commands over
|
||||
* vendor-type USB messages.
|
||||
*/
|
||||
|
||||
#define HDA_VERB_CMD(V, N, D) (((N) << 20) | ((V) << 8) | (D))
|
||||
|
||||
#define REALTEK_HDA_VALUE 0x0038
|
||||
|
||||
#define REALTEK_HDA_SET 62
|
||||
#define REALTEK_HDA_GET_OUT 88
|
||||
#define REALTEK_HDA_GET_IN 89
|
||||
|
||||
#define REALTEK_LINE1 0x1a
|
||||
#define REALTEK_VENDOR_REGISTERS 0x20
|
||||
#define REALTEK_HP_OUT 0x21
|
||||
|
||||
#define REALTEK_CBJ_CTRL2 0x50
|
||||
|
||||
#define REALTEK_JACK_INTERRUPT_NODE 5
|
||||
|
||||
#define REALTEK_MIC_FLAG 0x100
|
||||
|
||||
static int realtek_hda_set(struct snd_usb_audio *chip, u32 cmd)
|
||||
{
|
||||
struct usb_device *dev = chip->dev;
|
||||
__be32 buf = cpu_to_be32(cmd);
|
||||
|
||||
return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_HDA_SET,
|
||||
USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
REALTEK_HDA_VALUE, 0, &buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int realtek_hda_get(struct snd_usb_audio *chip, u32 cmd, u32 *value)
|
||||
{
|
||||
struct usb_device *dev = chip->dev;
|
||||
int err;
|
||||
__be32 buf = cpu_to_be32(cmd);
|
||||
|
||||
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_HDA_GET_OUT,
|
||||
USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
REALTEK_HDA_VALUE, 0, &buf, sizeof(buf));
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), REALTEK_HDA_GET_IN,
|
||||
USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
REALTEK_HDA_VALUE, 0, &buf, sizeof(buf));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*value = be32_to_cpu(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int realtek_ctl_connector_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct usb_mixer_elem_info *cval = kcontrol->private_data;
|
||||
struct snd_usb_audio *chip = cval->head.mixer->chip;
|
||||
u32 pv = kcontrol->private_value;
|
||||
u32 node_id = pv & 0xff;
|
||||
u32 sense;
|
||||
u32 cbj_ctrl2;
|
||||
bool presence;
|
||||
int err;
|
||||
|
||||
err = snd_usb_lock_shutdown(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = realtek_hda_get(chip,
|
||||
HDA_VERB_CMD(AC_VERB_GET_PIN_SENSE, node_id, 0),
|
||||
&sense);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
if (pv & REALTEK_MIC_FLAG) {
|
||||
err = realtek_hda_set(chip,
|
||||
HDA_VERB_CMD(AC_VERB_SET_COEF_INDEX,
|
||||
REALTEK_VENDOR_REGISTERS,
|
||||
REALTEK_CBJ_CTRL2));
|
||||
if (err < 0)
|
||||
goto err;
|
||||
err = realtek_hda_get(chip,
|
||||
HDA_VERB_CMD(AC_VERB_GET_PROC_COEF,
|
||||
REALTEK_VENDOR_REGISTERS, 0),
|
||||
&cbj_ctrl2);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
snd_usb_unlock_shutdown(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
presence = sense & AC_PINSENSE_PRESENCE;
|
||||
if (pv & REALTEK_MIC_FLAG)
|
||||
presence = presence && (cbj_ctrl2 & 0x0070) == 0x0070;
|
||||
ucontrol->value.integer.value[0] = presence;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new realtek_connector_ctl_ro = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
|
||||
.name = "", /* will be filled later manually */
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ,
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = realtek_ctl_connector_get,
|
||||
};
|
||||
|
||||
static int realtek_resume_jack(struct usb_mixer_elem_list *list)
|
||||
{
|
||||
snd_ctl_notify(list->mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&list->kctl->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int realtek_add_jack(struct usb_mixer_interface *mixer,
|
||||
char *name, u32 val)
|
||||
{
|
||||
struct usb_mixer_elem_info *cval;
|
||||
struct snd_kcontrol *kctl;
|
||||
|
||||
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
|
||||
if (!cval)
|
||||
return -ENOMEM;
|
||||
snd_usb_mixer_elem_init_std(&cval->head, mixer,
|
||||
REALTEK_JACK_INTERRUPT_NODE);
|
||||
cval->head.resume = realtek_resume_jack;
|
||||
cval->val_type = USB_MIXER_BOOLEAN;
|
||||
cval->channels = 1;
|
||||
cval->min = 0;
|
||||
cval->max = 1;
|
||||
kctl = snd_ctl_new1(&realtek_connector_ctl_ro, cval);
|
||||
if (!kctl) {
|
||||
kfree(cval);
|
||||
return -ENOMEM;
|
||||
}
|
||||
kctl->private_value = val;
|
||||
strscpy(kctl->id.name, name, sizeof(kctl->id.name));
|
||||
kctl->private_free = snd_usb_mixer_elem_free;
|
||||
return snd_usb_mixer_add_control(&cval->head, kctl);
|
||||
}
|
||||
|
||||
static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = realtek_add_jack(mixer, "Line Out Jack", REALTEK_LINE1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = realtek_add_jack(mixer, "Headphone Jack", REALTEK_HP_OUT);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = realtek_add_jack(mixer, "Headset Mic Jack",
|
||||
REALTEK_HP_OUT | REALTEK_MIC_FLAG);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
|
||||
{
|
||||
u16 buf = 0;
|
||||
@@ -1823,6 +1988,380 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RME Class Compliant device quirks */
|
||||
|
||||
#define SND_RME_GET_STATUS1 23
|
||||
#define SND_RME_GET_CURRENT_FREQ 17
|
||||
#define SND_RME_CLK_SYSTEM_SHIFT 16
|
||||
#define SND_RME_CLK_SYSTEM_MASK 0x1f
|
||||
#define SND_RME_CLK_AES_SHIFT 8
|
||||
#define SND_RME_CLK_SPDIF_SHIFT 12
|
||||
#define SND_RME_CLK_AES_SPDIF_MASK 0xf
|
||||
#define SND_RME_CLK_SYNC_SHIFT 6
|
||||
#define SND_RME_CLK_SYNC_MASK 0x3
|
||||
#define SND_RME_CLK_FREQMUL_SHIFT 18
|
||||
#define SND_RME_CLK_FREQMUL_MASK 0x7
|
||||
#define SND_RME_CLK_SYSTEM(x) \
|
||||
((x >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK)
|
||||
#define SND_RME_CLK_AES(x) \
|
||||
((x >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK)
|
||||
#define SND_RME_CLK_SPDIF(x) \
|
||||
((x >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK)
|
||||
#define SND_RME_CLK_SYNC(x) \
|
||||
((x >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK)
|
||||
#define SND_RME_CLK_FREQMUL(x) \
|
||||
((x >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK)
|
||||
#define SND_RME_CLK_AES_LOCK 0x1
|
||||
#define SND_RME_CLK_AES_SYNC 0x4
|
||||
#define SND_RME_CLK_SPDIF_LOCK 0x2
|
||||
#define SND_RME_CLK_SPDIF_SYNC 0x8
|
||||
#define SND_RME_SPDIF_IF_SHIFT 4
|
||||
#define SND_RME_SPDIF_FORMAT_SHIFT 5
|
||||
#define SND_RME_BINARY_MASK 0x1
|
||||
#define SND_RME_SPDIF_IF(x) \
|
||||
((x >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK)
|
||||
#define SND_RME_SPDIF_FORMAT(x) \
|
||||
((x >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK)
|
||||
|
||||
static const u32 snd_rme_rate_table[] = {
|
||||
32000, 44100, 48000, 50000,
|
||||
64000, 88200, 96000, 100000,
|
||||
128000, 176400, 192000, 200000,
|
||||
256000, 352800, 384000, 400000,
|
||||
512000, 705600, 768000, 800000
|
||||
};
|
||||
/* maximum number of items for AES and S/PDIF rates for above table */
|
||||
#define SND_RME_RATE_IDX_AES_SPDIF_NUM 12
|
||||
|
||||
enum snd_rme_domain {
|
||||
SND_RME_DOMAIN_SYSTEM,
|
||||
SND_RME_DOMAIN_AES,
|
||||
SND_RME_DOMAIN_SPDIF
|
||||
};
|
||||
|
||||
enum snd_rme_clock_status {
|
||||
SND_RME_CLOCK_NOLOCK,
|
||||
SND_RME_CLOCK_LOCK,
|
||||
SND_RME_CLOCK_SYNC
|
||||
};
|
||||
|
||||
static int snd_rme_read_value(struct snd_usb_audio *chip,
|
||||
unsigned int item,
|
||||
u32 *value)
|
||||
{
|
||||
struct usb_device *dev = chip->dev;
|
||||
int err;
|
||||
|
||||
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
item,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||
0, 0,
|
||||
value, sizeof(*value));
|
||||
if (err < 0)
|
||||
dev_err(&dev->dev,
|
||||
"unable to issue vendor read request %d (ret = %d)",
|
||||
item, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_rme_get_status1(struct snd_kcontrol *kcontrol,
|
||||
u32 *status1)
|
||||
{
|
||||
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_usb_audio *chip = list->mixer->chip;
|
||||
int err;
|
||||
|
||||
err = snd_usb_lock_shutdown(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1);
|
||||
snd_usb_unlock_shutdown(chip);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_rme_rate_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u32 status1;
|
||||
u32 rate = 0;
|
||||
int idx;
|
||||
int err;
|
||||
|
||||
err = snd_rme_get_status1(kcontrol, &status1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
switch (kcontrol->private_value) {
|
||||
case SND_RME_DOMAIN_SYSTEM:
|
||||
idx = SND_RME_CLK_SYSTEM(status1);
|
||||
if (idx < ARRAY_SIZE(snd_rme_rate_table))
|
||||
rate = snd_rme_rate_table[idx];
|
||||
break;
|
||||
case SND_RME_DOMAIN_AES:
|
||||
idx = SND_RME_CLK_AES(status1);
|
||||
if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM)
|
||||
rate = snd_rme_rate_table[idx];
|
||||
break;
|
||||
case SND_RME_DOMAIN_SPDIF:
|
||||
idx = SND_RME_CLK_SPDIF(status1);
|
||||
if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM)
|
||||
rate = snd_rme_rate_table[idx];
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ucontrol->value.integer.value[0] = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_rme_sync_state_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u32 status1;
|
||||
int idx = SND_RME_CLOCK_NOLOCK;
|
||||
int err;
|
||||
|
||||
err = snd_rme_get_status1(kcontrol, &status1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
switch (kcontrol->private_value) {
|
||||
case SND_RME_DOMAIN_AES: /* AES */
|
||||
if (status1 & SND_RME_CLK_AES_SYNC)
|
||||
idx = SND_RME_CLOCK_SYNC;
|
||||
else if (status1 & SND_RME_CLK_AES_LOCK)
|
||||
idx = SND_RME_CLOCK_LOCK;
|
||||
break;
|
||||
case SND_RME_DOMAIN_SPDIF: /* SPDIF */
|
||||
if (status1 & SND_RME_CLK_SPDIF_SYNC)
|
||||
idx = SND_RME_CLOCK_SYNC;
|
||||
else if (status1 & SND_RME_CLK_SPDIF_LOCK)
|
||||
idx = SND_RME_CLOCK_LOCK;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ucontrol->value.enumerated.item[0] = idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_rme_spdif_if_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u32 status1;
|
||||
int err;
|
||||
|
||||
err = snd_rme_get_status1(kcontrol, &status1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_IF(status1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_rme_spdif_format_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u32 status1;
|
||||
int err;
|
||||
|
||||
err = snd_rme_get_status1(kcontrol, &status1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_FORMAT(status1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_rme_sync_source_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
u32 status1;
|
||||
int err;
|
||||
|
||||
err = snd_rme_get_status1(kcontrol, &status1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ucontrol->value.enumerated.item[0] = SND_RME_CLK_SYNC(status1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_rme_current_freq_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_usb_audio *chip = list->mixer->chip;
|
||||
u32 status1;
|
||||
const u64 num = 104857600000000ULL;
|
||||
u32 den;
|
||||
unsigned int freq;
|
||||
int err;
|
||||
|
||||
err = snd_usb_lock_shutdown(chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, &status1);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
err = snd_rme_read_value(chip, SND_RME_GET_CURRENT_FREQ, &den);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
freq = (den == 0) ? 0 : div64_u64(num, den);
|
||||
freq <<= SND_RME_CLK_FREQMUL(status1);
|
||||
ucontrol->value.integer.value[0] = freq;
|
||||
|
||||
end:
|
||||
snd_usb_unlock_shutdown(chip);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_rme_rate_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
switch (kcontrol->private_value) {
|
||||
case SND_RME_DOMAIN_SYSTEM:
|
||||
uinfo->value.integer.min = 32000;
|
||||
uinfo->value.integer.max = 800000;
|
||||
break;
|
||||
case SND_RME_DOMAIN_AES:
|
||||
case SND_RME_DOMAIN_SPDIF:
|
||||
default:
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 200000;
|
||||
}
|
||||
uinfo->value.integer.step = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_rme_sync_state_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static const char *const sync_states[] = {
|
||||
"No Lock", "Lock", "Sync"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1,
|
||||
ARRAY_SIZE(sync_states), sync_states);
|
||||
}
|
||||
|
||||
static int snd_rme_spdif_if_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static const char *const spdif_if[] = {
|
||||
"Coaxial", "Optical"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1,
|
||||
ARRAY_SIZE(spdif_if), spdif_if);
|
||||
}
|
||||
|
||||
static int snd_rme_spdif_format_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static const char *const optical_type[] = {
|
||||
"Consumer", "Professional"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1,
|
||||
ARRAY_SIZE(optical_type), optical_type);
|
||||
}
|
||||
|
||||
static int snd_rme_sync_source_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static const char *const sync_sources[] = {
|
||||
"Internal", "AES", "SPDIF", "Internal"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1,
|
||||
ARRAY_SIZE(sync_sources), sync_sources);
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new snd_rme_controls[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "AES Rate",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_rate_info,
|
||||
.get = snd_rme_rate_get,
|
||||
.private_value = SND_RME_DOMAIN_AES
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "AES Sync",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_sync_state_info,
|
||||
.get = snd_rme_sync_state_get,
|
||||
.private_value = SND_RME_DOMAIN_AES
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "SPDIF Rate",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_rate_info,
|
||||
.get = snd_rme_rate_get,
|
||||
.private_value = SND_RME_DOMAIN_SPDIF
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "SPDIF Sync",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_sync_state_info,
|
||||
.get = snd_rme_sync_state_get,
|
||||
.private_value = SND_RME_DOMAIN_SPDIF
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "SPDIF Interface",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_spdif_if_info,
|
||||
.get = snd_rme_spdif_if_get,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "SPDIF Format",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_spdif_format_info,
|
||||
.get = snd_rme_spdif_format_get,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Sync Source",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_sync_source_info,
|
||||
.get = snd_rme_sync_source_get
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "System Rate",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_rate_info,
|
||||
.get = snd_rme_rate_get,
|
||||
.private_value = SND_RME_DOMAIN_SYSTEM
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Current Frequency",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.info = snd_rme_rate_info,
|
||||
.get = snd_rme_current_freq_get
|
||||
}
|
||||
};
|
||||
|
||||
static int snd_rme_controls_create(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(snd_rme_controls); ++i) {
|
||||
err = add_single_ctl_with_resume(mixer, 0,
|
||||
NULL,
|
||||
&snd_rme_controls[i],
|
||||
NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
int err = 0;
|
||||
@@ -1908,8 +2447,20 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
|
||||
err = snd_soundblaster_e1_switch_create(mixer);
|
||||
break;
|
||||
case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */
|
||||
err = dell_dock_mixer_create(mixer);
|
||||
if (err < 0)
|
||||
break;
|
||||
err = dell_dock_mixer_init(mixer);
|
||||
break;
|
||||
case USB_ID(0x0bda, 0x402e): /* Dell WD19 dock */
|
||||
err = dell_dock_mixer_create(mixer);
|
||||
break;
|
||||
|
||||
case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */
|
||||
case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */
|
||||
case USB_ID(0x2a39, 0x3fd4): /* RME */
|
||||
err = snd_rme_controls_create(mixer);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user