Skip to content

Commit

Permalink
Merge branch 'topic/misc' into for-linus
Browse files Browse the repository at this point in the history
  • Loading branch information
Takashi Iwai committed Oct 26, 2011
2 parents 5cdf745 + dde7ad8 commit d226657
Show file tree
Hide file tree
Showing 86 changed files with 2,025 additions and 1,584 deletions.
36 changes: 21 additions & 15 deletions Documentation/DocBook/writing-an-alsa-driver.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4288,7 +4288,7 @@ struct _snd_pcm_runtime {
<![CDATA[
struct snd_rawmidi *rmidi;
snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, info_flags,
irq, irq_flags, &rmidi);
irq, &rmidi);
]]>
</programlisting>
</informalexample>
Expand Down Expand Up @@ -4343,6 +4343,13 @@ struct _snd_pcm_runtime {
by itself to start processing the output stream in the irq handler.
</para>

<para>
If the MPU-401 interface shares its interrupt with the other logical
devices on the card, set <constant>MPU401_INFO_IRQ_HOOK</constant>
(see <link linkend="midi-interface-interrupt-handler"><citetitle>
below</citetitle></link>).
</para>

<para>
Usually, the port address corresponds to the command port and
port + 1 corresponds to the data port. If not, you may change
Expand Down Expand Up @@ -4375,27 +4382,26 @@ struct _snd_pcm_runtime {
</para>

<para>
The 6th argument specifies the irq number for UART. If the irq
is already allocated, pass 0 to the 7th argument
(<parameter>irq_flags</parameter>). Otherwise, pass the flags
for irq allocation
(<constant>SA_XXX</constant> bits) to it, and the irq will be
reserved by the mpu401-uart layer. If the card doesn't generate
UART interrupts, pass -1 as the irq number. Then a timer
interrupt will be invoked for polling.
The 6th argument specifies the ISA irq number that will be
allocated. If no interrupt is to be allocated (because your
code is already allocating a shared interrupt, or because the
device does not use interrupts), pass -1 instead.
For a MPU-401 device without an interrupt, a polling timer
will be used instead.
</para>
</section>

<section id="midi-interface-interrupt-handler">
<title>Interrupt Handler</title>
<para>
When the interrupt is allocated in
<function>snd_mpu401_uart_new()</function>, the private
interrupt handler is used, hence you don't have anything else to do
than creating the mpu401 stuff. Otherwise, you have to call
<function>snd_mpu401_uart_interrupt()</function> explicitly when
a UART interrupt is invoked and checked in your own interrupt
handler.
<function>snd_mpu401_uart_new()</function>, an exclusive ISA
interrupt handler is automatically used, hence you don't have
anything else to do than creating the mpu401 stuff. Otherwise, you
have to set <constant>MPU401_INFO_IRQ_HOOK</constant>, and call
<function>snd_mpu401_uart_interrupt()</function> explicitly from your
own interrupt handler when it has determined that a UART interrupt
has occurred.
</para>

<para>
Expand Down
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -5990,7 +5990,7 @@ M: Jaroslav Kysela <perex@perex.cz>
M: Takashi Iwai <tiwai@suse.de>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://www.alsa-project.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
T: git git://git.alsa-project.org/alsa-kernel.git
S: Maintained
F: Documentation/sound/
Expand Down
17 changes: 11 additions & 6 deletions include/linux/usb/ch9.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,19 +377,24 @@ struct usb_endpoint_descriptor {
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80

#define USB_ENDPOINT_SYNCTYPE 0x0c
#define USB_ENDPOINT_SYNC_NONE (0 << 2)
#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2)
#define USB_ENDPOINT_SYNC_SYNC (3 << 2)

#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80

#define USB_ENDPOINT_SYNCTYPE 0x0c
#define USB_ENDPOINT_SYNC_NONE (0 << 2)
#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2)
#define USB_ENDPOINT_SYNC_SYNC (3 << 2)

#define USB_ENDPOINT_USAGE_MASK 0x30
#define USB_ENDPOINT_USAGE_DATA 0x00
#define USB_ENDPOINT_USAGE_FEEDBACK 0x10
#define USB_ENDPOINT_USAGE_IMPLICIT_FB 0x20 /* Implicit feedback Data endpoint */

/*-------------------------------------------------------------------------*/

/**
Expand Down
4 changes: 3 additions & 1 deletion include/sound/asound.h
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ struct snd_timer_tread {
* *
****************************************************************************/

#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7)

struct snd_ctl_card_info {
int card; /* card number */
Expand Down Expand Up @@ -803,6 +803,8 @@ struct snd_ctl_elem_info {
unsigned int items; /* R: number of items */
unsigned int item; /* W: item number */
char name[64]; /* R: value name */
__u64 names_ptr; /* W: names list (ELEM_ADD only) */
unsigned int names_length;
} enumerated;
unsigned char reserved[128];
} value;
Expand Down
7 changes: 4 additions & 3 deletions include/sound/mpu401.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@
#define MPU401_INFO_INTEGRATED (1 << 2) /* integrated h/w port */
#define MPU401_INFO_MMIO (1 << 3) /* MMIO access */
#define MPU401_INFO_TX_IRQ (1 << 4) /* independent TX irq */
#define MPU401_INFO_IRQ_HOOK (1 << 5) /* mpu401 irq handler is called
from driver irq handler */
#define MPU401_INFO_NO_ACK (1 << 6) /* No ACK cmd needed */
#define MPU401_INFO_USE_TIMER (1 << 15) /* internal */

#define MPU401_MODE_BIT_INPUT 0
#define MPU401_MODE_BIT_OUTPUT 1
Expand All @@ -73,8 +76,7 @@ struct snd_mpu401 {
unsigned long port; /* base port of MPU-401 chip */
unsigned long cport; /* port + 1 (usually) */
struct resource *res; /* port resource */
int irq; /* IRQ number of MPU-401 chip (-1 = poll) */
int irq_flags;
int irq; /* IRQ number of MPU-401 chip */

unsigned long mode; /* MPU401_MODE_XXXX */
int timer_invoked;
Expand Down Expand Up @@ -131,7 +133,6 @@ int snd_mpu401_uart_new(struct snd_card *card,
unsigned long port,
unsigned int info_flags,
int irq,
int irq_flags,
struct snd_rawmidi ** rrawmidi);

#endif /* __SOUND_MPU401_H */
2 changes: 2 additions & 0 deletions include/sound/pcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,8 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
unsigned int cond,
snd_pcm_hw_param_t var);
int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
unsigned int base_rate);
int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime,
unsigned int cond,
int var,
Expand Down
4 changes: 1 addition & 3 deletions sound/aoa/codecs/onyx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,6 @@ static int onyx_i2c_probe(struct i2c_client *client,
printk(KERN_DEBUG PFX "created and attached onyx instance\n");
return 0;
fail:
i2c_set_clientdata(client, NULL);
kfree(onyx);
return -ENODEV;
}
Expand Down Expand Up @@ -1112,8 +1111,7 @@ static int onyx_i2c_remove(struct i2c_client *client)

aoa_codec_unregister(&onyx->codec);
of_node_put(onyx->codec.node);
if (onyx->codec_info)
kfree(onyx->codec_info);
kfree(onyx->codec_info);
kfree(onyx);
return 0;
}
Expand Down
84 changes: 78 additions & 6 deletions sound/core/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,6 @@ struct user_element {
void *tlv_data; /* TLV data */
unsigned long tlv_data_size; /* TLV data size */
void *priv_data; /* private data (like strings for enumerated type) */
unsigned long priv_data_size; /* size of private data in bytes */
};

static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
Expand All @@ -1001,6 +1000,28 @@ static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
return 0;
}

static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct user_element *ue = kcontrol->private_data;
const char *names;
unsigned int item;

item = uinfo->value.enumerated.item;

*uinfo = ue->info;

item = min(item, uinfo->value.enumerated.items - 1);
uinfo->value.enumerated.item = item;

names = ue->priv_data;
for (; item > 0; --item)
names += strlen(names) + 1;
strcpy(uinfo->value.enumerated.name, names);

return 0;
}

static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
Expand Down Expand Up @@ -1055,11 +1076,46 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
return change;
}

static int snd_ctl_elem_init_enum_names(struct user_element *ue)
{
char *names, *p;
size_t buf_len, name_len;
unsigned int i;

if (ue->info.value.enumerated.names_length > 64 * 1024)
return -EINVAL;

names = memdup_user(
(const void __user *)ue->info.value.enumerated.names_ptr,
ue->info.value.enumerated.names_length);
if (IS_ERR(names))
return PTR_ERR(names);

/* check that there are enough valid names */
buf_len = ue->info.value.enumerated.names_length;
p = names;
for (i = 0; i < ue->info.value.enumerated.items; ++i) {
name_len = strnlen(p, buf_len);
if (name_len == 0 || name_len >= 64 || name_len == buf_len) {
kfree(names);
return -EINVAL;
}
p += name_len + 1;
buf_len -= name_len + 1;
}

ue->priv_data = names;
ue->info.value.enumerated.names_ptr = 0;

return 0;
}

static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
{
struct user_element *ue = kcontrol->private_data;
if (ue->tlv_data)
kfree(ue->tlv_data);

kfree(ue->tlv_data);
kfree(ue->priv_data);
kfree(ue);
}

Expand All @@ -1072,8 +1128,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
long private_size;
struct user_element *ue;
int idx, err;
if (card->user_ctl_count >= MAX_USER_CONTROLS)

if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
return -ENOMEM;
if (info->count < 1)
return -EINVAL;
Expand Down Expand Up @@ -1101,7 +1157,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
memcpy(&kctl.id, &info->id, sizeof(info->id));
kctl.count = info->owner ? info->owner : 1;
access |= SNDRV_CTL_ELEM_ACCESS_USER;
kctl.info = snd_ctl_elem_user_info;
if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
kctl.info = snd_ctl_elem_user_enum_info;
else
kctl.info = snd_ctl_elem_user_info;
if (access & SNDRV_CTL_ELEM_ACCESS_READ)
kctl.get = snd_ctl_elem_user_get;
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
Expand All @@ -1122,6 +1181,11 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
if (info->count > 64)
return -EINVAL;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
private_size = sizeof(unsigned int);
if (info->count > 128 || info->value.enumerated.items == 0)
return -EINVAL;
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
private_size = sizeof(unsigned char);
if (info->count > 512)
Expand All @@ -1143,9 +1207,17 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
ue->info.access = 0;
ue->elem_data = (char *)ue + sizeof(*ue);
ue->elem_data_size = private_size;
if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
err = snd_ctl_elem_init_enum_names(ue);
if (err < 0) {
kfree(ue);
return err;
}
}
kctl.private_free = snd_ctl_elem_user_free;
_kctl = snd_ctl_new(&kctl, access);
if (_kctl == NULL) {
kfree(ue->priv_data);
kfree(ue);
return -ENOMEM;
}
Expand Down
4 changes: 4 additions & 0 deletions sound/core/control_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ struct snd_ctl_elem_info32 {
u32 items;
u32 item;
char name[64];
u64 names_ptr;
u32 names_length;
} enumerated;
unsigned char reserved[128];
} value;
Expand Down Expand Up @@ -372,6 +374,8 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
&data32->value.enumerated,
sizeof(data->value.enumerated)))
goto error;
data->value.enumerated.names_ptr =
(uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
break;
default:
break;
Expand Down
2 changes: 1 addition & 1 deletion sound/core/oss/mixer_oss.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c

memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strcpy(id.name, name);
strlcpy(id.name, name, sizeof(id.name));
id.index = index;
return snd_ctl_find_id(card, &id);
}
Expand Down
26 changes: 26 additions & 0 deletions sound/core/pcm_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,32 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,

EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);

static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
unsigned int base_rate = (unsigned int)(uintptr_t)rule->private;
struct snd_interval *rate;

rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
return snd_interval_list(rate, 1, &base_rate, 0);
}

/**
* snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling
* @runtime: PCM runtime instance
* @base_rate: the rate at which the hardware does not resample
*/
int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
unsigned int base_rate)
{
return snd_pcm_hw_rule_add(runtime, SNDRV_PCM_HW_PARAMS_NORESAMPLE,
SNDRV_PCM_HW_PARAM_RATE,
snd_pcm_hw_rule_noresample_func,
(void *)(uintptr_t)base_rate,
SNDRV_PCM_HW_PARAM_RATE, -1);
}
EXPORT_SYMBOL(snd_pcm_hw_rule_noresample);

static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var)
{
Expand Down
Loading

0 comments on commit d226657

Please sign in to comment.