Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/tiwai/sound-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (41 commits)
  ALSA: hda - Identify more variants for ALC269
  ALSA: hda - Fix wrong ALC269 variant check
  ALSA: hda - Enable jack sense for Thinkpad Edge 11
  ALSA: Revert "ALSA: hda - Fix switching between dmic and mic using the same mux on IDT/STAC"
  ALSA: hda - Fixed ALC887-VD initial error
  ALSA: atmel - Fix the return value in error path
  ALSA: hda: Use hp-laptop quirk to enable headphones automute for Asus A52J
  ALSA: snd-atmel-abdac: test wrong variable
  ALSA: azt3328: period bug fix (for PA), add missing ACK on stop timer
  ALSA: hda: Add Samsung R720 SSID for subwoofer pin fixup
  ALSA: sound/pci/asihpi/hpioctl.c: Remove unnecessary casts of pci_get_drvdata
  ALSA: sound/core/pcm_lib.c: Remove unnecessary semicolons
  ALSA: sound/ppc: Use printf extension %pR for struct resource
  ALSA: ac97: Apply quirk for Dell Latitude D610 binding Master and Headphone controls
  ASoC: uda134x - set reg_cache_default to uda134x_reg
  ASoC: Add support for MAX98089 CODEC
  ASoC: davinci: fixes for multi-component
  ASoC: Fix register cache setup WM8994 for multi-component
  ASoC: Fix dapm_seq_compare() for multi-component
  ASoC: RX1950: Fix hw_params function
  ...
  • Loading branch information
Linus Torvalds committed Nov 23, 2010
2 parents a4ec046 + 9e8c32c commit ea49b16
Show file tree
Hide file tree
Showing 48 changed files with 375 additions and 259 deletions.
6 changes: 3 additions & 3 deletions arch/arm/mach-davinci/dm355.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,8 @@ static struct clk_lookup dm355_clks[] = {
CLK(NULL, "uart1", &uart1_clk),
CLK(NULL, "uart2", &uart2_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK("davinci-asp.0", NULL, &asp0_clk),
CLK("davinci-asp.1", NULL, &asp1_clk),
CLK("davinci-mcbsp.0", NULL, &asp0_clk),
CLK("davinci-mcbsp.1", NULL, &asp1_clk),
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
CLK("spi_davinci.0", NULL, &spi0_clk),
Expand Down Expand Up @@ -664,7 +664,7 @@ static struct resource dm355_asp1_resources[] = {
};

static struct platform_device dm355_asp1_device = {
.name = "davinci-asp",
.name = "davinci-mcbsp",
.id = 1,
.num_resources = ARRAY_SIZE(dm355_asp1_resources),
.resource = dm355_asp1_resources,
Expand Down
6 changes: 3 additions & 3 deletions arch/arm/mach-davinci/dm365.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ static struct clk_lookup dm365_clks[] = {
CLK(NULL, "usb", &usb_clk),
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("davinci_voicecodec", NULL, &voicecodec_clk),
CLK("davinci-asp.0", NULL, &asp0_clk),
CLK("davinci-mcbsp", NULL, &asp0_clk),
CLK(NULL, "rto", &rto_clk),
CLK(NULL, "mjcp", &mjcp_clk),
CLK(NULL, NULL, NULL),
Expand Down Expand Up @@ -922,8 +922,8 @@ static struct resource dm365_asp_resources[] = {
};

static struct platform_device dm365_asp_device = {
.name = "davinci-asp",
.id = 0,
.name = "davinci-mcbsp",
.id = -1,
.num_resources = ARRAY_SIZE(dm365_asp_resources),
.resource = dm365_asp_resources,
};
Expand Down
4 changes: 2 additions & 2 deletions arch/arm/mach-davinci/dm644x.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ static struct clk_lookup dm644x_clks[] = {
CLK("davinci_emac.1", NULL, &emac_clk),
CLK("i2c_davinci.1", NULL, &i2c_clk),
CLK("palm_bk3710", NULL, &ide_clk),
CLK("davinci-asp", NULL, &asp_clk),
CLK("davinci-mcbsp", NULL, &asp_clk),
CLK("davinci_mmc.0", NULL, &mmcsd_clk),
CLK(NULL, "spi", &spi_clk),
CLK(NULL, "gpio", &gpio_clk),
Expand Down Expand Up @@ -580,7 +580,7 @@ static struct resource dm644x_asp_resources[] = {
};

static struct platform_device dm644x_asp_device = {
.name = "davinci-asp",
.name = "davinci-mcbsp",
.id = -1,
.num_resources = ARRAY_SIZE(dm644x_asp_resources),
.resource = dm644x_asp_resources,
Expand Down
3 changes: 0 additions & 3 deletions include/linux/mfd/wm8350/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,6 @@
#define WM8350_MCLK_SEL_PLL_32K 3
#define WM8350_MCLK_SEL_MCLK 5

#define WM8350_MCLK_DIR_OUT 0
#define WM8350_MCLK_DIR_IN 1

/* clock divider id's */
#define WM8350_ADC_CLKDIV 0
#define WM8350_DAC_CLKDIV 1
Expand Down
4 changes: 2 additions & 2 deletions sound/atmel/abdac.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,9 +420,9 @@ static int __devinit atmel_abdac_probe(struct platform_device *pdev)
return PTR_ERR(pclk);
}
sample_clk = clk_get(&pdev->dev, "sample_clk");
if (IS_ERR(pclk)) {
if (IS_ERR(sample_clk)) {
dev_dbg(&pdev->dev, "no sample clock\n");
retval = PTR_ERR(pclk);
retval = PTR_ERR(sample_clk);
goto out_put_pclk;
}
clk_enable(pclk);
Expand Down
2 changes: 1 addition & 1 deletion sound/core/pcm_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ static void xrun_log(struct snd_pcm_substream *substream,
entry->jiffies = jiffies;
entry->pos = pos;
entry->period_size = runtime->period_size;
entry->buffer_size = runtime->buffer_size;;
entry->buffer_size = runtime->buffer_size;
entry->old_hw_ptr = runtime->status->hw_ptr;
entry->hw_ptr_base = runtime->hw_ptr_base;
log->idx = (log->idx + 1) % XRUN_LOG_CNT;
Expand Down
6 changes: 2 additions & 4 deletions sound/oss/dev_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
if (sound_nblocks >= MAX_MEM_BLOCKS)
sound_nblocks = MAX_MEM_BLOCKS - 1;

op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations)));
op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct audio_operations)));
sound_nblocks++;
if (sound_nblocks >= MAX_MEM_BLOCKS)
sound_nblocks = MAX_MEM_BLOCKS - 1;
Expand All @@ -81,7 +81,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
sound_unload_audiodev(num);
return -(ENOMEM);
}
memset((char *) op, 0, sizeof(struct audio_operations));
init_waitqueue_head(&op->in_sleeper);
init_waitqueue_head(&op->out_sleeper);
init_waitqueue_head(&op->poll_sleeper);
Expand Down Expand Up @@ -128,7 +127,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
/* FIXME: This leaks a mixer_operations struct every time its called
until you unload sound! */

op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations)));
op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vzalloc(sizeof(struct mixer_operations)));
sound_nblocks++;
if (sound_nblocks >= MAX_MEM_BLOCKS)
sound_nblocks = MAX_MEM_BLOCKS - 1;
Expand All @@ -137,7 +136,6 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name);
return -ENOMEM;
}
memset((char *) op, 0, sizeof(struct mixer_operations));
memcpy((char *) op, (char *) driver, driver_size);

strlcpy(op->name, name, sizeof(op->name));
Expand Down
4 changes: 2 additions & 2 deletions sound/oss/midibuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ int MIDIbuf_open(int dev, struct file *file)
return err;

parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));

if (midi_in_buf[dev] == NULL)
{
Expand All @@ -188,7 +188,7 @@ int MIDIbuf_open(int dev, struct file *file)
}
midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;

midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));

if (midi_out_buf[dev] == NULL)
{
Expand Down
6 changes: 3 additions & 3 deletions sound/oss/pss.c
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,
return 0;

case SNDCTL_COPR_LOAD:
buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
buf = vmalloc(sizeof(copr_buffer));
if (buf == NULL)
return -ENOSPC;
if (copy_from_user(buf, arg, sizeof(copr_buffer))) {
Expand All @@ -871,7 +871,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,
return err;

case SNDCTL_COPR_SENDMSG:
mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
mbuf = vmalloc(sizeof(copr_msg));
if (mbuf == NULL)
return -ENOSPC;
if (copy_from_user(mbuf, arg, sizeof(copr_msg))) {
Expand All @@ -895,7 +895,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg,

case SNDCTL_COPR_RCVMSG:
err = 0;
mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
mbuf = vmalloc(sizeof(copr_msg));
if (mbuf == NULL)
return -ENOSPC;
data = (unsigned short *)mbuf->data;
Expand Down
4 changes: 2 additions & 2 deletions sound/oss/sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1646,13 +1646,13 @@ void sequencer_init(void)
{
if (sequencer_ok)
return;
queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ);
if (queue == NULL)
{
printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n");
return;
}
iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
if (iqueue == NULL)
{
printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n");
Expand Down
2 changes: 1 addition & 1 deletion sound/pci/asihpi/hpioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
struct hpi_message hm;
struct hpi_response hr;
struct hpi_adapter *pa;
pa = (struct hpi_adapter *)pci_get_drvdata(pci_dev);
pa = pci_get_drvdata(pci_dev);

hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DELETE_ADAPTER);
Expand Down
26 changes: 18 additions & 8 deletions sound/pci/azt3328.c
Original file line number Diff line number Diff line change
Expand Up @@ -1129,10 +1129,11 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,

count_areas = size/2;
addr_area2 = addr+count_areas;
count_areas--; /* max. index */
snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n",
addr, count_areas, addr_area2, count_areas);

count_areas--; /* max. index */

/* build combined I/O buffer length word */
lengths = (count_areas << 16) | (count_areas);
spin_lock_irqsave(&chip->reg_lock, flags);
Expand Down Expand Up @@ -1740,11 +1741,15 @@ static const struct snd_pcm_hardware snd_azf3328_hardware =
.rate_max = AZF_FREQ_66200,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 65536,
.period_bytes_min = 64,
.period_bytes_max = 65536,
.periods_min = 1,
.periods_max = 1024,
.buffer_bytes_max = (64*1024),
.period_bytes_min = 1024,
.period_bytes_max = (32*1024),
/* We simply have two DMA areas (instead of a list of descriptors
such as other cards); I believe that this is a fixed hardware
attribute and there isn't much driver magic to be done to expand it.
Thus indicate that we have at least and at most 2 periods. */
.periods_min = 2,
.periods_max = 2,
/* FIXME: maybe that card actually has a FIFO?
* Hmm, it seems newer revisions do have one, but we still don't know
* its size... */
Expand Down Expand Up @@ -1980,8 +1985,13 @@ snd_azf3328_timer_stop(struct snd_timer *timer)
chip = snd_timer_chip(timer);
spin_lock_irqsave(&chip->reg_lock, flags);
/* disable timer countdown and interrupt */
/* FIXME: should we write TIMER_IRQ_ACK here? */
snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0);
/* Hmm, should we write TIMER_IRQ_ACK here?
YES indeed, otherwise a rogue timer operation - which prompts
ALSA(?) to call repeated stop() in vain, but NOT start() -
will never end (value 0x03 is kept shown in control byte).
Simply manually poking 0x04 _once_ immediately successfully stops
the hardware/ALSA interrupt activity. */
snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_azf3328_dbgcallleave();
return 0;
Expand Down
16 changes: 10 additions & 6 deletions sound/pci/ctxfi/ctpcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)

apcm->substream = substream;
apcm->interrupt = ct_atc_pcm_interrupt;
runtime->private_data = apcm;
runtime->private_free = ct_atc_pcm_free_substream;
if (IEC958 == substream->pcm->device) {
runtime->hw = ct_spdif_passthru_playback_hw;
atc->spdif_out_passthru(atc, 1);
Expand All @@ -155,8 +153,12 @@ static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
}

apcm->timer = ct_timer_instance_new(atc->timer, apcm);
if (!apcm->timer)
if (!apcm->timer) {
kfree(apcm);
return -ENOMEM;
}
runtime->private_data = apcm;
runtime->private_free = ct_atc_pcm_free_substream;

return 0;
}
Expand Down Expand Up @@ -278,8 +280,6 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
apcm->started = 0;
apcm->substream = substream;
apcm->interrupt = ct_atc_pcm_interrupt;
runtime->private_data = apcm;
runtime->private_free = ct_atc_pcm_free_substream;
runtime->hw = ct_pcm_capture_hw;
runtime->hw.rate_max = atc->rsr * atc->msr;

Expand All @@ -298,8 +298,12 @@ static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
}

apcm->timer = ct_timer_instance_new(atc->timer, apcm);
if (!apcm->timer)
if (!apcm->timer) {
kfree(apcm);
return -ENOMEM;
}
runtime->private_data = apcm;
runtime->private_free = ct_atc_pcm_free_substream;

return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions sound/pci/hda/patch_conexant.c
Original file line number Diff line number Diff line change
Expand Up @@ -3100,6 +3100,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP),
SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
Expand All @@ -3110,6 +3111,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD),
Expand Down
28 changes: 22 additions & 6 deletions sound/pci/hda/patch_realtek.c
Original file line number Diff line number Diff line change
Expand Up @@ -14623,7 +14623,10 @@ static int alc275_setup_dual_adc(struct hda_codec *codec)
/* different alc269-variants */
enum {
ALC269_TYPE_NORMAL,
ALC269_TYPE_ALC258,
ALC269_TYPE_ALC259,
ALC269_TYPE_ALC269VB,
ALC269_TYPE_ALC270,
ALC269_TYPE_ALC271X,
};

Expand Down Expand Up @@ -15023,7 +15026,7 @@ static int alc269_fill_coef(struct hda_codec *codec)
static int patch_alc269(struct hda_codec *codec)
{
struct alc_spec *spec;
int board_config;
int board_config, coef;
int err;

spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Expand All @@ -15034,14 +15037,23 @@ static int patch_alc269(struct hda_codec *codec)

alc_auto_parse_customize_define(codec);

if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
coef = alc_read_coef_idx(codec, 0);
if ((coef & 0x00f0) == 0x0010) {
if (codec->bus->pci->subsystem_vendor == 0x1025 &&
spec->cdefine.platform_type == 1) {
alc_codec_rename(codec, "ALC271X");
spec->codec_variant = ALC269_TYPE_ALC271X;
} else {
} else if ((coef & 0xf000) == 0x1000) {
spec->codec_variant = ALC269_TYPE_ALC270;
} else if ((coef & 0xf000) == 0x2000) {
alc_codec_rename(codec, "ALC259");
spec->codec_variant = ALC269_TYPE_ALC259;
} else if ((coef & 0xf000) == 0x3000) {
alc_codec_rename(codec, "ALC258");
spec->codec_variant = ALC269_TYPE_ALC258;
} else {
alc_codec_rename(codec, "ALC269VB");
spec->codec_variant = ALC269_TYPE_ALC269VB;
}
} else
alc_fix_pll_init(codec, 0x20, 0x04, 15);
Expand Down Expand Up @@ -15104,7 +15116,7 @@ static int patch_alc269(struct hda_codec *codec)
spec->stream_digital_capture = &alc269_pcm_digital_capture;

if (!spec->adc_nids) { /* wasn't filled automatically? use default */
if (spec->codec_variant != ALC269_TYPE_NORMAL) {
if (spec->codec_variant == ALC269_TYPE_NORMAL) {
spec->adc_nids = alc269_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
spec->capsrc_nids = alc269_capsrc_nids;
Expand Down Expand Up @@ -19298,6 +19310,7 @@ static const struct alc_fixup alc662_fixups[] = {

static struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
{}
Expand Down Expand Up @@ -19419,7 +19432,10 @@ static int patch_alc888(struct hda_codec *codec)
{
if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
kfree(codec->chip_name);
codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
if (codec->vendor_id == 0x10ec0887)
codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
else
codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
if (!codec->chip_name) {
alc_free(codec);
return -ENOMEM;
Expand Down Expand Up @@ -19909,7 +19925,7 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
.patch = patch_alc882 },
{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
{ .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
{ .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
{ .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
.patch = patch_alc882 },
{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Expand Down
Loading

0 comments on commit ea49b16

Please sign in to comment.