2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-18 02:04:05 +08:00

Merge branch 'topic/misc' into for-linus

This commit is contained in:
Takashi Iwai 2011-10-26 23:51:43 +02:00
commit d226657022
86 changed files with 2061 additions and 1620 deletions

View File

@ -4288,7 +4288,7 @@ struct _snd_pcm_runtime {
<![CDATA[ <![CDATA[
struct snd_rawmidi *rmidi; struct snd_rawmidi *rmidi;
snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, info_flags, snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, info_flags,
irq, irq_flags, &rmidi); irq, &rmidi);
]]> ]]>
</programlisting> </programlisting>
</informalexample> </informalexample>
@ -4343,6 +4343,13 @@ struct _snd_pcm_runtime {
by itself to start processing the output stream in the irq handler. by itself to start processing the output stream in the irq handler.
</para> </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> <para>
Usually, the port address corresponds to the command port and Usually, the port address corresponds to the command port and
port + 1 corresponds to the data port. If not, you may change port + 1 corresponds to the data port. If not, you may change
@ -4375,14 +4382,12 @@ struct _snd_pcm_runtime {
</para> </para>
<para> <para>
The 6th argument specifies the irq number for UART. If the irq The 6th argument specifies the ISA irq number that will be
is already allocated, pass 0 to the 7th argument allocated. If no interrupt is to be allocated (because your
(<parameter>irq_flags</parameter>). Otherwise, pass the flags code is already allocating a shared interrupt, or because the
for irq allocation device does not use interrupts), pass -1 instead.
(<constant>SA_XXX</constant> bits) to it, and the irq will be For a MPU-401 device without an interrupt, a polling timer
reserved by the mpu401-uart layer. If the card doesn't generate will be used instead.
UART interrupts, pass -1 as the irq number. Then a timer
interrupt will be invoked for polling.
</para> </para>
</section> </section>
@ -4390,12 +4395,13 @@ struct _snd_pcm_runtime {
<title>Interrupt Handler</title> <title>Interrupt Handler</title>
<para> <para>
When the interrupt is allocated in When the interrupt is allocated in
<function>snd_mpu401_uart_new()</function>, the private <function>snd_mpu401_uart_new()</function>, an exclusive ISA
interrupt handler is used, hence you don't have anything else to do interrupt handler is automatically used, hence you don't have
than creating the mpu401 stuff. Otherwise, you have to call anything else to do than creating the mpu401 stuff. Otherwise, you
<function>snd_mpu401_uart_interrupt()</function> explicitly when have to set <constant>MPU401_INFO_IRQ_HOOK</constant>, and call
a UART interrupt is invoked and checked in your own interrupt <function>snd_mpu401_uart_interrupt()</function> explicitly from your
handler. own interrupt handler when it has determined that a UART interrupt
has occurred.
</para> </para>
<para> <para>

View File

@ -5990,7 +5990,7 @@ M: Jaroslav Kysela <perex@perex.cz>
M: Takashi Iwai <tiwai@suse.de> M: Takashi Iwai <tiwai@suse.de>
L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://www.alsa-project.org/ 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 T: git git://git.alsa-project.org/alsa-kernel.git
S: Maintained S: Maintained
F: Documentation/sound/ F: Documentation/sound/

View File

@ -377,12 +377,6 @@ struct usb_endpoint_descriptor {
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ #define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80 #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_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0 #define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1 #define USB_ENDPOINT_XFER_ISOC 1
@ -390,6 +384,17 @@ struct usb_endpoint_descriptor {
#define USB_ENDPOINT_XFER_INT 3 #define USB_ENDPOINT_XFER_INT 3
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 #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 */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/** /**

View File

@ -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 { struct snd_ctl_card_info {
int card; /* card number */ int card; /* card number */
@ -803,6 +803,8 @@ struct snd_ctl_elem_info {
unsigned int items; /* R: number of items */ unsigned int items; /* R: number of items */
unsigned int item; /* W: item number */ unsigned int item; /* W: item number */
char name[64]; /* R: value name */ char name[64]; /* R: value name */
__u64 names_ptr; /* W: names list (ELEM_ADD only) */
unsigned int names_length;
} enumerated; } enumerated;
unsigned char reserved[128]; unsigned char reserved[128];
} value; } value;

View File

@ -50,7 +50,10 @@
#define MPU401_INFO_INTEGRATED (1 << 2) /* integrated h/w port */ #define MPU401_INFO_INTEGRATED (1 << 2) /* integrated h/w port */
#define MPU401_INFO_MMIO (1 << 3) /* MMIO access */ #define MPU401_INFO_MMIO (1 << 3) /* MMIO access */
#define MPU401_INFO_TX_IRQ (1 << 4) /* independent TX irq */ #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_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_INPUT 0
#define MPU401_MODE_BIT_OUTPUT 1 #define MPU401_MODE_BIT_OUTPUT 1
@ -73,8 +76,7 @@ struct snd_mpu401 {
unsigned long port; /* base port of MPU-401 chip */ unsigned long port; /* base port of MPU-401 chip */
unsigned long cport; /* port + 1 (usually) */ unsigned long cport; /* port + 1 (usually) */
struct resource *res; /* port resource */ struct resource *res; /* port resource */
int irq; /* IRQ number of MPU-401 chip (-1 = poll) */ int irq; /* IRQ number of MPU-401 chip */
int irq_flags;
unsigned long mode; /* MPU401_MODE_XXXX */ unsigned long mode; /* MPU401_MODE_XXXX */
int timer_invoked; int timer_invoked;
@ -131,7 +133,6 @@ int snd_mpu401_uart_new(struct snd_card *card,
unsigned long port, unsigned long port,
unsigned int info_flags, unsigned int info_flags,
int irq, int irq,
int irq_flags,
struct snd_rawmidi ** rrawmidi); struct snd_rawmidi ** rrawmidi);
#endif /* __SOUND_MPU401_H */ #endif /* __SOUND_MPU401_H */

View File

@ -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, int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
unsigned int cond, unsigned int cond,
snd_pcm_hw_param_t var); 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, int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime,
unsigned int cond, unsigned int cond,
int var, int var,

View File

@ -1067,7 +1067,6 @@ static int onyx_i2c_probe(struct i2c_client *client,
printk(KERN_DEBUG PFX "created and attached onyx instance\n"); printk(KERN_DEBUG PFX "created and attached onyx instance\n");
return 0; return 0;
fail: fail:
i2c_set_clientdata(client, NULL);
kfree(onyx); kfree(onyx);
return -ENODEV; return -ENODEV;
} }
@ -1112,8 +1111,7 @@ static int onyx_i2c_remove(struct i2c_client *client)
aoa_codec_unregister(&onyx->codec); aoa_codec_unregister(&onyx->codec);
of_node_put(onyx->codec.node); of_node_put(onyx->codec.node);
if (onyx->codec_info) kfree(onyx->codec_info);
kfree(onyx->codec_info);
kfree(onyx); kfree(onyx);
return 0; return 0;
} }

View File

@ -989,7 +989,6 @@ struct user_element {
void *tlv_data; /* TLV data */ void *tlv_data; /* TLV data */
unsigned long tlv_data_size; /* TLV data size */ unsigned long tlv_data_size; /* TLV data size */
void *priv_data; /* private data (like strings for enumerated type) */ 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, static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
@ -1001,6 +1000,28 @@ static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
return 0; 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, static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
@ -1055,11 +1076,46 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
return change; 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) static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
{ {
struct user_element *ue = kcontrol->private_data; 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); kfree(ue);
} }
@ -1073,7 +1129,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
struct user_element *ue; struct user_element *ue;
int idx, err; int idx, err;
if (card->user_ctl_count >= MAX_USER_CONTROLS) if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
return -ENOMEM; return -ENOMEM;
if (info->count < 1) if (info->count < 1)
return -EINVAL; return -EINVAL;
@ -1101,7 +1157,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
memcpy(&kctl.id, &info->id, sizeof(info->id)); memcpy(&kctl.id, &info->id, sizeof(info->id));
kctl.count = info->owner ? info->owner : 1; kctl.count = info->owner ? info->owner : 1;
access |= SNDRV_CTL_ELEM_ACCESS_USER; 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) if (access & SNDRV_CTL_ELEM_ACCESS_READ)
kctl.get = snd_ctl_elem_user_get; kctl.get = snd_ctl_elem_user_get;
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
@ -1122,6 +1181,11 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
if (info->count > 64) if (info->count > 64)
return -EINVAL; return -EINVAL;
break; 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: case SNDRV_CTL_ELEM_TYPE_BYTES:
private_size = sizeof(unsigned char); private_size = sizeof(unsigned char);
if (info->count > 512) if (info->count > 512)
@ -1143,9 +1207,17 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
ue->info.access = 0; ue->info.access = 0;
ue->elem_data = (char *)ue + sizeof(*ue); ue->elem_data = (char *)ue + sizeof(*ue);
ue->elem_data_size = private_size; 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.private_free = snd_ctl_elem_user_free;
_kctl = snd_ctl_new(&kctl, access); _kctl = snd_ctl_new(&kctl, access);
if (_kctl == NULL) { if (_kctl == NULL) {
kfree(ue->priv_data);
kfree(ue); kfree(ue);
return -ENOMEM; return -ENOMEM;
} }

View File

@ -83,6 +83,8 @@ struct snd_ctl_elem_info32 {
u32 items; u32 items;
u32 item; u32 item;
char name[64]; char name[64];
u64 names_ptr;
u32 names_length;
} enumerated; } enumerated;
unsigned char reserved[128]; unsigned char reserved[128];
} value; } value;
@ -372,6 +374,8 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
&data32->value.enumerated, &data32->value.enumerated,
sizeof(data->value.enumerated))) sizeof(data->value.enumerated)))
goto error; goto error;
data->value.enumerated.names_ptr =
(uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
break; break;
default: default:
break; break;

View File

@ -499,7 +499,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c
memset(&id, 0, sizeof(id)); memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strcpy(id.name, name); strlcpy(id.name, name, sizeof(id.name));
id.index = index; id.index = index;
return snd_ctl_find_id(card, &id); return snd_ctl_find_id(card, &id);
} }

View File

@ -1399,6 +1399,32 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); 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, static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var) snd_pcm_hw_param_t var)
{ {

View File

@ -2058,16 +2058,12 @@ EXPORT_SYMBOL(snd_pcm_open_substream);
static int snd_pcm_open_file(struct file *file, static int snd_pcm_open_file(struct file *file,
struct snd_pcm *pcm, struct snd_pcm *pcm,
int stream, int stream)
struct snd_pcm_file **rpcm_file)
{ {
struct snd_pcm_file *pcm_file; struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
int err; int err;
if (rpcm_file)
*rpcm_file = NULL;
err = snd_pcm_open_substream(pcm, stream, file, &substream); err = snd_pcm_open_substream(pcm, stream, file, &substream);
if (err < 0) if (err < 0)
return err; return err;
@ -2083,8 +2079,7 @@ static int snd_pcm_open_file(struct file *file,
substream->pcm_release = pcm_release_private; substream->pcm_release = pcm_release_private;
} }
file->private_data = pcm_file; file->private_data = pcm_file;
if (rpcm_file)
*rpcm_file = pcm_file;
return 0; return 0;
} }
@ -2113,7 +2108,6 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
{ {
int err; int err;
struct snd_pcm_file *pcm_file;
wait_queue_t wait; wait_queue_t wait;
if (pcm == NULL) { if (pcm == NULL) {
@ -2131,7 +2125,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
add_wait_queue(&pcm->open_wait, &wait); add_wait_queue(&pcm->open_wait, &wait);
mutex_lock(&pcm->open_mutex); mutex_lock(&pcm->open_mutex);
while (1) { while (1) {
err = snd_pcm_open_file(file, pcm, stream, &pcm_file); err = snd_pcm_open_file(file, pcm, stream);
if (err >= 0) if (err >= 0)
break; break;
if (err == -EAGAIN) { if (err == -EAGAIN) {

View File

@ -575,7 +575,8 @@ static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
static int loopback_hw_params(struct snd_pcm_substream *substream, static int loopback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); return snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(params));
} }
static int loopback_hw_free(struct snd_pcm_substream *substream) static int loopback_hw_free(struct snd_pcm_substream *substream)
@ -587,7 +588,7 @@ static int loopback_hw_free(struct snd_pcm_substream *substream)
mutex_lock(&dpcm->loopback->cable_lock); mutex_lock(&dpcm->loopback->cable_lock);
cable->valid &= ~(1 << substream->stream); cable->valid &= ~(1 << substream->stream);
mutex_unlock(&dpcm->loopback->cable_lock); mutex_unlock(&dpcm->loopback->cable_lock);
return snd_pcm_lib_free_pages(substream); return snd_pcm_lib_free_vmalloc_buffer(substream);
} }
static unsigned int get_cable_index(struct snd_pcm_substream *substream) static unsigned int get_cable_index(struct snd_pcm_substream *substream)
@ -740,6 +741,8 @@ static struct snd_pcm_ops loopback_playback_ops = {
.prepare = loopback_prepare, .prepare = loopback_prepare,
.trigger = loopback_trigger, .trigger = loopback_trigger,
.pointer = loopback_pointer, .pointer = loopback_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
.mmap = snd_pcm_lib_mmap_vmalloc,
}; };
static struct snd_pcm_ops loopback_capture_ops = { static struct snd_pcm_ops loopback_capture_ops = {
@ -751,6 +754,8 @@ static struct snd_pcm_ops loopback_capture_ops = {
.prepare = loopback_prepare, .prepare = loopback_prepare,
.trigger = loopback_trigger, .trigger = loopback_trigger,
.pointer = loopback_pointer, .pointer = loopback_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
.mmap = snd_pcm_lib_mmap_vmalloc,
}; };
static int __devinit loopback_pcm_new(struct loopback *loopback, static int __devinit loopback_pcm_new(struct loopback *loopback,
@ -771,10 +776,6 @@ static int __devinit loopback_pcm_new(struct loopback *loopback,
strcpy(pcm->name, "Loopback PCM"); strcpy(pcm->name, "Loopback PCM");
loopback->pcm[device] = pcm; loopback->pcm[device] = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL),
0, 2 * 1024 * 1024);
return 0; return 0;
} }

View File

@ -86,8 +86,7 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard)
} }
err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], 0, err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], 0,
irq[dev], irq[dev] >= 0 ? IRQF_DISABLED : 0, irq[dev], NULL);
NULL);
if (err < 0) { if (err < 0) {
printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]); printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]);
goto _err; goto _err;

View File

@ -3,7 +3,7 @@
* Routines for control of MPU-401 in UART mode * Routines for control of MPU-401 in UART mode
* *
* MPU-401 supports UART mode which is not capable generate transmit * MPU-401 supports UART mode which is not capable generate transmit
* interrupts thus output is done via polling. Also, if irq < 0, then * interrupts thus output is done via polling. Without interrupt,
* input is done also via polling. Do not expect good performance. * input is done also via polling. Do not expect good performance.
* *
* *
@ -374,7 +374,7 @@ snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
/* first time - flush FIFO */ /* first time - flush FIFO */
while (max-- > 0) while (max-- > 0)
mpu->read(mpu, MPU401D(mpu)); mpu->read(mpu, MPU401D(mpu));
if (mpu->irq < 0) if (mpu->info_flags & MPU401_INFO_USE_TIMER)
snd_mpu401_uart_add_timer(mpu, 1); snd_mpu401_uart_add_timer(mpu, 1);
} }
@ -383,7 +383,7 @@ snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
snd_mpu401_uart_input_read(mpu); snd_mpu401_uart_input_read(mpu);
spin_unlock_irqrestore(&mpu->input_lock, flags); spin_unlock_irqrestore(&mpu->input_lock, flags);
} else { } else {
if (mpu->irq < 0) if (mpu->info_flags & MPU401_INFO_USE_TIMER)
snd_mpu401_uart_remove_timer(mpu, 1); snd_mpu401_uart_remove_timer(mpu, 1);
clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
} }
@ -496,7 +496,7 @@ static struct snd_rawmidi_ops snd_mpu401_uart_input =
static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
{ {
struct snd_mpu401 *mpu = rmidi->private_data; struct snd_mpu401 *mpu = rmidi->private_data;
if (mpu->irq_flags && mpu->irq >= 0) if (mpu->irq >= 0)
free_irq(mpu->irq, (void *) mpu); free_irq(mpu->irq, (void *) mpu);
release_and_free_resource(mpu->res); release_and_free_resource(mpu->res);
kfree(mpu); kfree(mpu);
@ -509,8 +509,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
* @hardware: the hardware type, MPU401_HW_XXXX * @hardware: the hardware type, MPU401_HW_XXXX
* @port: the base address of MPU401 port * @port: the base address of MPU401 port
* @info_flags: bitflags MPU401_INFO_XXX * @info_flags: bitflags MPU401_INFO_XXX
* @irq: the irq number, -1 if no interrupt for mpu * @irq: the ISA irq number, -1 if not to be allocated
* @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved.
* @rrawmidi: the pointer to store the new rawmidi instance * @rrawmidi: the pointer to store the new rawmidi instance
* *
* Creates a new MPU-401 instance. * Creates a new MPU-401 instance.
@ -525,7 +524,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
unsigned short hardware, unsigned short hardware,
unsigned long port, unsigned long port,
unsigned int info_flags, unsigned int info_flags,
int irq, int irq_flags, int irq,
struct snd_rawmidi ** rrawmidi) struct snd_rawmidi ** rrawmidi)
{ {
struct snd_mpu401 *mpu; struct snd_mpu401 *mpu;
@ -577,8 +576,8 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
mpu->cport = port + 2; mpu->cport = port + 2;
else else
mpu->cport = port + 1; mpu->cport = port + 1;
if (irq >= 0 && irq_flags) { if (irq >= 0) {
if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, if (request_irq(irq, snd_mpu401_uart_interrupt, IRQF_DISABLED,
"MPU401 UART", (void *) mpu)) { "MPU401 UART", (void *) mpu)) {
snd_printk(KERN_ERR "mpu401_uart: " snd_printk(KERN_ERR "mpu401_uart: "
"unable to grab IRQ %d\n", irq); "unable to grab IRQ %d\n", irq);
@ -586,9 +585,10 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
return -EBUSY; return -EBUSY;
} }
} }
if (irq < 0 && !(info_flags & MPU401_INFO_IRQ_HOOK))
info_flags |= MPU401_INFO_USE_TIMER;
mpu->info_flags = info_flags; mpu->info_flags = info_flags;
mpu->irq = irq; mpu->irq = irq;
mpu->irq_flags = irq_flags;
if (card->shortname[0]) if (card->shortname[0])
snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI",
card->shortname); card->shortname);

View File

@ -51,7 +51,6 @@ struct isight {
struct fw_unit *unit; struct fw_unit *unit;
struct fw_device *device; struct fw_device *device;
u64 audio_base; u64 audio_base;
struct fw_address_handler iris_handler;
struct snd_pcm_substream *pcm; struct snd_pcm_substream *pcm;
struct mutex mutex; struct mutex mutex;
struct iso_packets_buffer buffer; struct iso_packets_buffer buffer;

View File

@ -778,9 +778,10 @@ static int __devexit fwspk_remove(struct device *dev)
{ {
struct fwspk *fwspk = dev_get_drvdata(dev); struct fwspk *fwspk = dev_get_drvdata(dev);
mutex_lock(&fwspk->mutex);
amdtp_out_stream_pcm_abort(&fwspk->stream); amdtp_out_stream_pcm_abort(&fwspk->stream);
snd_card_disconnect(fwspk->card); snd_card_disconnect(fwspk->card);
mutex_lock(&fwspk->mutex);
fwspk_stop_stream(fwspk); fwspk_stop_stream(fwspk);
mutex_unlock(&fwspk->mutex); mutex_unlock(&fwspk->mutex);
@ -796,8 +797,8 @@ static void fwspk_bus_reset(struct fw_unit *unit)
fcp_bus_reset(fwspk->unit); fcp_bus_reset(fwspk->unit);
if (cmp_connection_update(&fwspk->connection) < 0) { if (cmp_connection_update(&fwspk->connection) < 0) {
mutex_lock(&fwspk->mutex);
amdtp_out_stream_pcm_abort(&fwspk->stream); amdtp_out_stream_pcm_abort(&fwspk->stream);
mutex_lock(&fwspk->mutex);
fwspk_stop_stream(fwspk); fwspk_stop_stream(fwspk);
mutex_unlock(&fwspk->mutex); mutex_unlock(&fwspk->mutex);
return; return;

View File

@ -204,7 +204,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
if (mpu_port[dev] > 0) { if (mpu_port[dev] > 0) {
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port[dev], 0, mpu_irq[dev], IRQF_DISABLED, mpu_port[dev], 0, mpu_irq[dev],
NULL) < 0) NULL) < 0)
printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", mpu_port[dev]); printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", mpu_port[dev]);
} }

View File

@ -256,7 +256,6 @@ static int __devinit snd_card_als100_probe(int dev,
mpu_type, mpu_type,
mpu_port[dev], 0, mpu_port[dev], 0,
mpu_irq[dev], mpu_irq[dev],
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
NULL) < 0) NULL) < 0)
snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
} }

View File

@ -234,8 +234,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320, if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
mpu_port[dev], 0, mpu_port[dev], 0,
mpu_irq[dev], IRQF_DISABLED, mpu_irq[dev], NULL) < 0)
NULL) < 0)
snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
} }

View File

@ -597,7 +597,7 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
if (mpuport[dev] != SNDRV_AUTO_PORT) { if (mpuport[dev] != SNDRV_AUTO_PORT) {
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpuport[dev], 0, mpuirq[dev], mpuport[dev], 0, mpuirq[dev],
IRQF_DISABLED, NULL) < 0) NULL) < 0)
printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n", printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n",
mpuport[dev]); mpuport[dev]);
} }

View File

@ -131,7 +131,6 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n)
mpu_irq[n] = -1; mpu_irq[n] = -1;
if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232, if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232,
mpu_port[n], 0, mpu_irq[n], mpu_port[n], 0, mpu_irq[n],
mpu_irq[n] >= 0 ? IRQF_DISABLED : 0,
NULL) < 0) NULL) < 0)
dev_warn(dev, "MPU401 not detected\n"); dev_warn(dev, "MPU401 not detected\n");
} }

View File

@ -449,8 +449,7 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
mpu_irq[dev] = -1; mpu_irq[dev] = -1;
if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232, if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232,
mpu_port[dev], 0, mpu_port[dev], 0,
mpu_irq[dev], mpu_irq[dev], NULL) < 0)
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, NULL) < 0)
printk(KERN_WARNING IDENT ": MPU401 not detected\n"); printk(KERN_WARNING IDENT ": MPU401 not detected\n");
} }

View File

@ -174,7 +174,7 @@ static int __devinit snd_es1688_probe(struct snd_card *card, unsigned int n)
chip->mpu_port > 0) { chip->mpu_port > 0) {
error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688, error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
chip->mpu_port, 0, chip->mpu_port, 0,
mpu_irq[n], IRQF_DISABLED, NULL); mpu_irq[n], NULL);
if (error < 0) if (error < 0)
return error; return error;
} }

View File

@ -2160,8 +2160,8 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
mpu_port[dev], 0, mpu_port[dev], MPU401_INFO_IRQ_HOOK,
irq[dev], 0, &chip->rmidi); -1, &chip->rmidi);
if (err < 0) if (err < 0)
return err; return err;
} }

View File

@ -585,8 +585,7 @@ static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n)
if (mpu_port[n] >= 0) { if (mpu_port[n] >= 0) {
err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port[n], 0, mpu_irq[n], mpu_port[n], 0, mpu_irq[n], NULL);
IRQF_DISABLED, NULL);
if (err < 0) if (err < 0)
goto error; goto error;
} }

View File

@ -317,8 +317,7 @@ static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n)
if (es1688->mpu_port >= 0x300) { if (es1688->mpu_port >= 0x300) {
error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688, error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
es1688->mpu_port, 0, es1688->mpu_port, 0, mpu_irq[n], NULL);
mpu_irq[n], IRQF_DISABLED, NULL);
if (error < 0) if (error < 0)
goto out; goto out;
} }

View File

@ -600,7 +600,7 @@ static int __devinit snd_msnd_attach(struct snd_card *card)
mpu_io[0], mpu_io[0],
MPU401_MODE_INPUT | MPU401_MODE_INPUT |
MPU401_MODE_OUTPUT, MPU401_MODE_OUTPUT,
mpu_irq[0], IRQF_DISABLED, mpu_irq[0],
&chip->rmidi); &chip->rmidi);
if (err < 0) { if (err < 0) {
printk(KERN_ERR LOGNAME printk(KERN_ERR LOGNAME

View File

@ -707,8 +707,9 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
} }
if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) { if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2, if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2,
midi_port[dev], 0, midi_port[dev],
xirq, 0, &chip->rmidi)) < 0) MPU401_INFO_IRQ_HOOK, -1,
&chip->rmidi)) < 0)
return err; return err;
} }
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",

View File

@ -1377,8 +1377,7 @@ static int __devinit snd_miro_probe(struct snd_card *card)
rmidi = NULL; rmidi = NULL;
else { else {
error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, mpu_port, 0, miro->mpu_irq, &rmidi);
&rmidi);
if (error < 0) if (error < 0)
snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
mpu_port); mpu_port);

View File

@ -914,7 +914,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
rmidi = NULL; rmidi = NULL;
else { else {
error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi); mpu_port, 0, mpu_irq, &rmidi);
if (error) if (error)
snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
mpu_port); mpu_port);

View File

@ -322,7 +322,6 @@ static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev)
MPU401_HW_MPU401, MPU401_HW_MPU401,
mpu_port[dev], 0, mpu_port[dev], 0,
mpu_irq[dev], mpu_irq[dev],
mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
NULL) < 0) NULL) < 0)
snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n", snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n",
mpu_port[dev]); mpu_port[dev]);

View File

@ -394,8 +394,9 @@ static int __devinit snd_sb16_probe(struct snd_card *card, int dev)
if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB,
chip->mpu_port, 0, chip->mpu_port,
xirq, 0, &chip->rmidi)) < 0) MPU401_INFO_IRQ_HOOK, -1,
&chip->rmidi)) < 0)
return err; return err;
chip->rmidi_callback = snd_mpu401_uart_interrupt; chip->rmidi_callback = snd_mpu401_uart_interrupt;
} }

View File

@ -658,8 +658,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
if (snd_mpu401_uart_new(card, 0, if (snd_mpu401_uart_new(card, 0,
MPU401_HW_MPU401, MPU401_HW_MPU401,
mpu_port[dev], 0, mpu_port[dev], 0,
mpu_irq[dev], IRQF_DISABLED, mpu_irq[dev], NULL) < 0)
NULL) < 0)
snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n",
mpu_port[dev]); mpu_port[dev]);
} }

View File

@ -825,8 +825,7 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum,
int err; int err;
err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port, err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port,
MPU401_INFO_INTEGRATED, irq, IRQF_DISABLED, MPU401_INFO_INTEGRATED, irq, &rawmidi);
&rawmidi);
if (err == 0) { if (err == 0) {
struct snd_mpu401 *mpu = rawmidi->private_data; struct snd_mpu401 *mpu = rawmidi->private_data;
mpu->open_input = mpu401_open; mpu->open_input = mpu401_open;

View File

@ -449,8 +449,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) {
err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232, err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232,
cs4232_mpu_port[dev], 0, cs4232_mpu_port[dev], 0,
cs4232_mpu_irq[dev], IRQF_DISABLED, cs4232_mpu_irq[dev], NULL);
NULL);
if (err < 0) { if (err < 0) {
snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n"); snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n");
return err; return err;

View File

@ -320,7 +320,7 @@ void sound_timer_init(struct sound_lowlev_timer *t, char *name)
n = sound_alloc_timerdev(); n = sound_alloc_timerdev();
if (n == -1) if (n == -1)
n = 0; /* Overwrite the system timer */ n = 0; /* Overwrite the system timer */
strcpy(sound_timer.info.name, name); strlcpy(sound_timer.info.name, name, sizeof(sound_timer.info.name));
sound_timer_devs[n] = &sound_timer; sound_timer_devs[n] = &sound_timer;
} }
EXPORT_SYMBOL(sound_timer_init); EXPORT_SYMBOL(sound_timer_init);

View File

@ -931,8 +931,9 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000,
iobase + ALS4K_IOB_30_MIDI_DATA, iobase + ALS4K_IOB_30_MIDI_DATA,
MPU401_INFO_INTEGRATED, MPU401_INFO_INTEGRATED |
pci->irq, 0, &chip->rmidi)) < 0) { MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi)) < 0) {
printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n",
iobase + ALS4K_IOB_30_MIDI_DATA); iobase + ALS4K_IOB_30_MIDI_DATA);
goto out_err; goto out_err;

View File

@ -84,7 +84,7 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
#ifdef VORTEX_MPU401_LEGACY #ifdef VORTEX_MPU401_LEGACY
if ((temp = if ((temp =
snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330,
0, 0, 0, &rmidi)) != 0) { MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) {
hwwrite(vortex->mmio, VORTEX_CTRL, hwwrite(vortex->mmio, VORTEX_CTRL,
(hwread(vortex->mmio, VORTEX_CTRL) & (hwread(vortex->mmio, VORTEX_CTRL) &
~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
@ -94,8 +94,8 @@ static int __devinit snd_vortex_midi(vortex_t * vortex)
port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA);
if ((temp = if ((temp =
snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port,
MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO, MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO |
0, 0, &rmidi)) != 0) { MPU401_INFO_IRQ_HOOK, -1, &rmidi)) != 0) {
hwwrite(vortex->mmio, VORTEX_CTRL, hwwrite(vortex->mmio, VORTEX_CTRL,
(hwread(vortex->mmio, VORTEX_CTRL) & (hwread(vortex->mmio, VORTEX_CTRL) &
~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);

View File

@ -2652,8 +2652,9 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
since our hardware ought to be similar, thus use same ID. */ since our hardware ought to be similar, thus use same ID. */
err = snd_mpu401_uart_new( err = snd_mpu401_uart_new(
card, 0, card, 0,
MPU401_HW_AZT2320, chip->mpu_io, MPU401_INFO_INTEGRATED, MPU401_HW_AZT2320, chip->mpu_io,
pci->irq, 0, &chip->rmidi MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi
); );
if (err < 0) { if (err < 0) {
snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n",

View File

@ -3228,8 +3228,9 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
iomidi, iomidi,
(integrated_midi ? (integrated_midi ?
MPU401_INFO_INTEGRATED : 0), MPU401_INFO_INTEGRATED : 0) |
cm->irq, 0, &cm->rmidi)) < 0) { MPU401_INFO_IRQ_HOOK,
-1, &cm->rmidi)) < 0) {
printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi);
} }
} }

View File

@ -404,7 +404,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
int err; int err;
int playback_count, capture_count; int playback_count, capture_count;
playback_count = (IEC958 == device) ? 1 : 8; playback_count = (IEC958 == device) ? 1 : 256;
capture_count = (FRONT == device) ? 1 : 0; capture_count = (FRONT == device) ? 1 : 0;
err = snd_pcm_new(atc->card, "ctxfi", device, err = snd_pcm_new(atc->card, "ctxfi", device,
playback_count, capture_count, &pcm); playback_count, capture_count, &pcm);

View File

@ -20,7 +20,7 @@
#include "cthardware.h" #include "cthardware.h"
#include <linux/slab.h> #include <linux/slab.h>
#define SRC_RESOURCE_NUM 64 #define SRC_RESOURCE_NUM 256
#define SRCIMP_RESOURCE_NUM 256 #define SRCIMP_RESOURCE_NUM 256
static unsigned int conj_mask; static unsigned int conj_mask;

View File

@ -18,7 +18,7 @@
#ifndef CTVMEM_H #ifndef CTVMEM_H
#define CTVMEM_H #define CTVMEM_H
#define CT_PTP_NUM 1 /* num of device page table pages */ #define CT_PTP_NUM 4 /* num of device page table pages */
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/list.h> #include <linux/list.h>

View File

@ -1146,6 +1146,11 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
kfree(epcm); kfree(epcm);
return err; return err;
} }
err = snd_pcm_hw_rule_noresample(runtime, 48000);
if (err < 0) {
kfree(epcm);
return err;
}
mix = &emu->pcm_mixer[substream->number]; mix = &emu->pcm_mixer[substream->number];
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i; mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i;

View File

@ -1854,8 +1854,9 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci,
} }
} }
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
chip->mpu_port, MPU401_INFO_INTEGRATED, chip->mpu_port,
chip->irq, 0, &chip->rmidi) < 0) { MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi) < 0) {
printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); printk(KERN_ERR "es1938: unable to initialize MPU-401\n");
} else { } else {
// this line is vital for MIDI interrupt handling on ess-solo1 // this line is vital for MIDI interrupt handling on ess-solo1

View File

@ -2843,8 +2843,9 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci,
if (enable_mpu[dev]) { if (enable_mpu[dev]) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
chip->io_port + ESM_MPU401_PORT, chip->io_port + ESM_MPU401_PORT,
MPU401_INFO_INTEGRATED, MPU401_INFO_INTEGRATED |
chip->irq, 0, &chip->rmidi)) < 0) { MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi)) < 0) {
printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n");
} }
} }

View File

@ -729,11 +729,14 @@ static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = {
{ .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" }, { .data = 2, .clk = 0, .wren = 1, .most = 3, .name = "SF64-PCR" },
}; };
#define get_tea575x_gpio(chip) \
(&snd_fm801_tea575x_gpios[((chip)->tea575x_tuner & TUNER_TYPE_MASK) - 1])
static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
{ {
struct fm801 *chip = tea->private_data; struct fm801 *chip = tea->private_data;
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
reg &= ~(FM801_GPIO_GP(gpio.data) | reg &= ~(FM801_GPIO_GP(gpio.data) |
FM801_GPIO_GP(gpio.clk) | FM801_GPIO_GP(gpio.clk) |
@ -751,7 +754,7 @@ static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
{ {
struct fm801 *chip = tea->private_data; struct fm801 *chip = tea->private_data;
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 | return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 |
(reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0; (reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0;
@ -761,7 +764,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output
{ {
struct fm801 *chip = tea->private_data; struct fm801 *chip = tea->private_data;
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
struct snd_fm801_tea575x_gpio gpio = snd_fm801_tea575x_gpios[(chip->tea575x_tuner & TUNER_TYPE_MASK) - 1]; struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
/* use GPIO lines and set write enable bit */ /* use GPIO lines and set write enable bit */
reg |= FM801_GPIO_GS(gpio.data) | reg |= FM801_GPIO_GS(gpio.data) |
@ -1246,7 +1249,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
chip->tea575x_tuner = tea575x_tuner; chip->tea575x_tuner = tea575x_tuner;
if (!snd_tea575x_init(&chip->tea)) { if (!snd_tea575x_init(&chip->tea)) {
snd_printk(KERN_INFO "detected TEA575x radio type %s\n", snd_printk(KERN_INFO "detected TEA575x radio type %s\n",
snd_fm801_tea575x_gpios[tea575x_tuner - 1].name); get_tea575x_gpio(chip)->name);
break; break;
} }
} }
@ -1256,9 +1259,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
} }
} }
if (!(chip->tea575x_tuner & TUNER_DISABLED)) { if (!(chip->tea575x_tuner & TUNER_DISABLED)) {
strlcpy(chip->tea.card, strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
snd_fm801_tea575x_gpios[(tea575x_tuner &
TUNER_TYPE_MASK) - 1].name,
sizeof(chip->tea.card)); sizeof(chip->tea.card));
} }
#endif #endif
@ -1311,8 +1312,9 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
} }
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801,
FM801_REG(chip, MPU401_DATA), FM801_REG(chip, MPU401_DATA),
MPU401_INFO_INTEGRATED, MPU401_INFO_INTEGRATED |
chip->irq, 0, &chip->rmidi)) < 0) { MPU401_INFO_IRQ_HOOK,
-1, &chip->rmidi)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }

View File

@ -2748,8 +2748,9 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
if (!c->no_mpu401) { if (!c->no_mpu401) {
err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
ICEREG(ice, MPU1_CTRL), ICEREG(ice, MPU1_CTRL),
(c->mpu401_1_info_flags | MPU401_INFO_INTEGRATED), c->mpu401_1_info_flags |
ice->irq, 0, &ice->rmidi[0]); MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
-1, &ice->rmidi[0]);
if (err < 0) { if (err < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
@ -2764,8 +2765,9 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
/* 2nd port used */ /* 2nd port used */
err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712, err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712,
ICEREG(ice, MPU2_CTRL), ICEREG(ice, MPU2_CTRL),
(c->mpu401_2_info_flags | MPU401_INFO_INTEGRATED), c->mpu401_2_info_flags |
ice->irq, 0, &ice->rmidi[1]); MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
-1, &ice->rmidi[1]);
if (err < 0) { if (err < 0) {
snd_card_free(card); snd_card_free(card);

View File

@ -2820,8 +2820,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
/* TODO enable MIDI IRQ and I/O */ /* TODO enable MIDI IRQ and I/O */
err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401, err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401,
chip->iobase + MPU401_DATA_PORT, chip->iobase + MPU401_DATA_PORT,
MPU401_INFO_INTEGRATED, MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK,
chip->irq, 0, &chip->rmidi); -1, &chip->rmidi);
if (err < 0) if (err < 0)
printk(KERN_WARNING "maestro3: no MIDI support.\n"); printk(KERN_WARNING "maestro3: no MIDI support.\n");
#endif #endif

View File

@ -678,15 +678,15 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
goto err_card; goto err_card;
if (chip->model.device_config & (MIDI_OUTPUT | MIDI_INPUT)) { if (chip->model.device_config & (MIDI_OUTPUT | MIDI_INPUT)) {
unsigned int info_flags = MPU401_INFO_INTEGRATED; unsigned int info_flags =
MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK;
if (chip->model.device_config & MIDI_OUTPUT) if (chip->model.device_config & MIDI_OUTPUT)
info_flags |= MPU401_INFO_OUTPUT; info_flags |= MPU401_INFO_OUTPUT;
if (chip->model.device_config & MIDI_INPUT) if (chip->model.device_config & MIDI_INPUT)
info_flags |= MPU401_INFO_INPUT; info_flags |= MPU401_INFO_INPUT;
err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
chip->addr + OXYGEN_MPU401, chip->addr + OXYGEN_MPU401,
info_flags, 0, 0, info_flags, -1, &chip->midi);
&chip->midi);
if (err < 0) if (err < 0)
goto err_card; goto err_card;
} }

View File

@ -1074,6 +1074,7 @@ static const struct oxygen_model model_xonar_st = {
.device_config = PLAYBACK_0_TO_I2S | .device_config = PLAYBACK_0_TO_I2S |
PLAYBACK_1_TO_SPDIF | PLAYBACK_1_TO_SPDIF |
CAPTURE_0_FROM_I2S_2 | CAPTURE_0_FROM_I2S_2 |
CAPTURE_1_FROM_SPDIF |
AC97_FMIC_SWITCH, AC97_FMIC_SWITCH,
.dac_channels_pcm = 2, .dac_channels_pcm = 2,
.dac_channels_mixer = 2, .dac_channels_mixer = 2,

View File

@ -2109,7 +2109,7 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
val = mpu_port[dev]; val = mpu_port[dev];
pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, val); pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, val);
err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE, err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE,
val, 0, chip->irq, 0, val, MPU401_INFO_IRQ_HOOK, -1,
&chip->rmidi); &chip->rmidi);
if (err < 0) if (err < 0)
snd_printk(KERN_WARNING snd_printk(KERN_WARNING

View File

@ -1241,10 +1241,30 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
return rate; return rate;
} }
/* return latency in samples per period */
static int hdspm_get_latency(struct hdspm *hdspm)
{
int n;
n = hdspm_decode_latency(hdspm->control_register);
/* Special case for new RME cards with 32 samples period size.
* The three latency bits in the control register
* (HDSP_LatencyMask) encode latency values of 64 samples as
* 0, 128 samples as 1 ... 4096 samples as 6. For old cards, 7
* denotes 8192 samples, but on new cards like RayDAT or AIO,
* it corresponds to 32 samples.
*/
if ((7 == n) && (RayDAT == hdspm->io_type || AIO == hdspm->io_type))
n = -1;
return 1 << (n + 6);
}
/* Latency function */ /* Latency function */
static inline void hdspm_compute_period_size(struct hdspm *hdspm) static inline void hdspm_compute_period_size(struct hdspm *hdspm)
{ {
hdspm->period_bytes = 1 << ((hdspm_decode_latency(hdspm->control_register) + 8)); hdspm->period_bytes = 4 * hdspm_get_latency(hdspm);
} }
@ -1303,12 +1323,27 @@ static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames)
spin_lock_irq(&s->lock); spin_lock_irq(&s->lock);
frames >>= 7; if (32 == frames) {
n = 0; /* Special case for new RME cards like RayDAT/AIO which
while (frames) { * support period sizes of 32 samples. Since latency is
n++; * encoded in the three bits of HDSP_LatencyMask, we can only
frames >>= 1; * have values from 0 .. 7. While 0 still means 64 samples and
* 6 represents 4096 samples on all cards, 7 represents 8192
* on older cards and 32 samples on new cards.
*
* In other words, period size in samples is calculated by
* 2^(n+6) with n ranging from 0 .. 7.
*/
n = 7;
} else {
frames >>= 7;
n = 0;
while (frames) {
n++;
frames >>= 1;
}
} }
s->control_register &= ~HDSPM_LatencyMask; s->control_register &= ~HDSPM_LatencyMask;
s->control_register |= hdspm_encode_latency(n); s->control_register |= hdspm_encode_latency(n);
@ -4801,8 +4836,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
snd_iprintf(buffer, "--- Settings ---\n"); snd_iprintf(buffer, "--- Settings ---\n");
x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & x = hdspm_get_latency(hdspm);
HDSPM_LatencyMask));
snd_iprintf(buffer, snd_iprintf(buffer,
"Size (Latency): %d samples (2 periods of %lu bytes)\n", "Size (Latency): %d samples (2 periods of %lu bytes)\n",
@ -4965,8 +4999,7 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
snd_iprintf(buffer, "--- Settings ---\n"); snd_iprintf(buffer, "--- Settings ---\n");
x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & x = hdspm_get_latency(hdspm);
HDSPM_LatencyMask));
snd_iprintf(buffer, snd_iprintf(buffer,
"Size (Latency): %d samples (2 periods of %lu bytes)\n", "Size (Latency): %d samples (2 periods of %lu bytes)\n",
@ -5672,19 +5705,6 @@ static int snd_hdspm_prepare(struct snd_pcm_substream *substream)
return 0; return 0;
} }
static unsigned int period_sizes_old[] = {
64, 128, 256, 512, 1024, 2048, 4096
};
static unsigned int period_sizes_new[] = {
32, 64, 128, 256, 512, 1024, 2048, 4096
};
/* RayDAT and AIO always have a buffer of 16384 samples per channel */
static unsigned int raydat_aio_buffer_sizes[] = {
16384
};
static struct snd_pcm_hardware snd_hdspm_playback_subinfo = { static struct snd_pcm_hardware snd_hdspm_playback_subinfo = {
.info = (SNDRV_PCM_INFO_MMAP | .info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
@ -5703,8 +5723,8 @@ static struct snd_pcm_hardware snd_hdspm_playback_subinfo = {
.channels_max = HDSPM_MAX_CHANNELS, .channels_max = HDSPM_MAX_CHANNELS,
.buffer_bytes_max = .buffer_bytes_max =
HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
.period_bytes_min = (64 * 4), .period_bytes_min = (32 * 4),
.period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS, .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
.periods_min = 2, .periods_min = 2,
.periods_max = 512, .periods_max = 512,
.fifo_size = 0 .fifo_size = 0
@ -5728,31 +5748,13 @@ static struct snd_pcm_hardware snd_hdspm_capture_subinfo = {
.channels_max = HDSPM_MAX_CHANNELS, .channels_max = HDSPM_MAX_CHANNELS,
.buffer_bytes_max = .buffer_bytes_max =
HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS, HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
.period_bytes_min = (64 * 4), .period_bytes_min = (32 * 4),
.period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS, .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
.periods_min = 2, .periods_min = 2,
.periods_max = 512, .periods_max = 512,
.fifo_size = 0 .fifo_size = 0
}; };
static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes_old = {
.count = ARRAY_SIZE(period_sizes_old),
.list = period_sizes_old,
.mask = 0
};
static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes_new = {
.count = ARRAY_SIZE(period_sizes_new),
.list = period_sizes_new,
.mask = 0
};
static struct snd_pcm_hw_constraint_list hw_constraints_raydat_io_buffer = {
.count = ARRAY_SIZE(raydat_aio_buffer_sizes),
.list = raydat_aio_buffer_sizes,
.mask = 0
};
static int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params, static int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule) struct snd_pcm_hw_rule *rule)
{ {
@ -5953,26 +5955,29 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
spin_unlock_irq(&hdspm->lock); spin_unlock_irq(&hdspm->lock);
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
switch (hdspm->io_type) { switch (hdspm->io_type) {
case AIO: case AIO:
case RayDAT: case RayDAT:
snd_pcm_hw_constraint_list(runtime, 0, snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
&hw_constraints_period_sizes_new); 32, 4096);
snd_pcm_hw_constraint_list(runtime, 0, /* RayDAT & AIO have a fixed buffer of 16384 samples per channel */
SNDRV_PCM_HW_PARAM_BUFFER_SIZE, snd_pcm_hw_constraint_minmax(runtime,
&hw_constraints_raydat_io_buffer); SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
16384, 16384);
break; break;
default: default:
snd_pcm_hw_constraint_list(runtime, 0, snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
&hw_constraints_period_sizes_old); 64, 8192);
break;
} }
if (AES32 == hdspm->io_type) { if (AES32 == hdspm->io_type) {
runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hdspm_hw_constraints_aes32_sample_rates); &hdspm_hw_constraints_aes32_sample_rates);
} else { } else {
@ -6025,24 +6030,28 @@ static int snd_hdspm_capture_open(struct snd_pcm_substream *substream)
spin_unlock_irq(&hdspm->lock); spin_unlock_irq(&hdspm->lock);
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
switch (hdspm->io_type) { switch (hdspm->io_type) {
case AIO: case AIO:
case RayDAT: case RayDAT:
snd_pcm_hw_constraint_list(runtime, 0, snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
&hw_constraints_period_sizes_new); 32, 4096);
snd_pcm_hw_constraint_list(runtime, 0, snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
&hw_constraints_raydat_io_buffer); 16384, 16384);
break; break;
default: default:
snd_pcm_hw_constraint_list(runtime, 0, snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
&hw_constraints_period_sizes_old); 64, 8192);
break;
} }
if (AES32 == hdspm->io_type) { if (AES32 == hdspm->io_type) {
runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hdspm_hw_constraints_aes32_sample_rates); &hdspm_hw_constraints_aes32_sample_rates);
} else { } else {
@ -6088,7 +6097,7 @@ static inline int copy_u32_le(void __user *dest, void __iomem *src)
} }
static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
unsigned int cmd, unsigned long __user arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
struct hdspm *hdspm = hw->private_data; struct hdspm *hdspm = hw->private_data;
@ -6213,11 +6222,13 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
info.line_out = hdspm_line_out(hdspm); info.line_out = hdspm_line_out(hdspm);
info.passthru = 0; info.passthru = 0;
spin_unlock_irq(&hdspm->lock); spin_unlock_irq(&hdspm->lock);
if (copy_to_user((void __user *) arg, &info, sizeof(info))) if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT; return -EFAULT;
break; break;
case SNDRV_HDSPM_IOCTL_GET_STATUS: case SNDRV_HDSPM_IOCTL_GET_STATUS:
memset(&status, 0, sizeof(status));
status.card_type = hdspm->io_type; status.card_type = hdspm->io_type;
status.autosync_source = hdspm_autosync_ref(hdspm); status.autosync_source = hdspm_autosync_ref(hdspm);
@ -6250,13 +6261,15 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
break; break;
} }
if (copy_to_user((void __user *) arg, &status, sizeof(status))) if (copy_to_user(argp, &status, sizeof(status)))
return -EFAULT; return -EFAULT;
break; break;
case SNDRV_HDSPM_IOCTL_GET_VERSION: case SNDRV_HDSPM_IOCTL_GET_VERSION:
memset(&hdspm_version, 0, sizeof(hdspm_version));
hdspm_version.card_type = hdspm->io_type; hdspm_version.card_type = hdspm->io_type;
strncpy(hdspm_version.cardname, hdspm->card_name, strncpy(hdspm_version.cardname, hdspm->card_name,
sizeof(hdspm_version.cardname)); sizeof(hdspm_version.cardname));
@ -6267,13 +6280,13 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
if (hdspm->tco) if (hdspm->tco)
hdspm_version.addons |= HDSPM_ADDON_TCO; hdspm_version.addons |= HDSPM_ADDON_TCO;
if (copy_to_user((void __user *) arg, &hdspm_version, if (copy_to_user(argp, &hdspm_version,
sizeof(hdspm_version))) sizeof(hdspm_version)))
return -EFAULT; return -EFAULT;
break; break;
case SNDRV_HDSPM_IOCTL_GET_MIXER: case SNDRV_HDSPM_IOCTL_GET_MIXER:
if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) if (copy_from_user(&mixer, argp, sizeof(mixer)))
return -EFAULT; return -EFAULT;
if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer,
sizeof(struct hdspm_mixer))) sizeof(struct hdspm_mixer)))

View File

@ -1493,9 +1493,10 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci,
return err; return err;
} }
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES, if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES,
sonic->midi_port, MPU401_INFO_INTEGRATED, sonic->midi_port,
sonic->irq, 0, MPU401_INFO_INTEGRATED |
&midi_uart)) < 0) { MPU401_INFO_IRQ_HOOK,
-1, &midi_uart)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }

View File

@ -148,8 +148,9 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
if (trident->device != TRIDENT_DEVICE_ID_SI7018 && if (trident->device != TRIDENT_DEVICE_ID_SI7018 &&
(err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE,
trident->midi_port, trident->midi_port,
MPU401_INFO_INTEGRATED, MPU401_INFO_INTEGRATED |
trident->irq, 0, &trident->rmidi)) < 0) { MPU401_INFO_IRQ_HOOK,
-1, &trident->rmidi)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }

View File

@ -1175,6 +1175,7 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
int err; int err;
struct via_rate_lock *ratep; struct via_rate_lock *ratep;
bool use_src = false;
runtime->hw = snd_via82xx_hw; runtime->hw = snd_via82xx_hw;
@ -1196,6 +1197,7 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
SNDRV_PCM_RATE_8000_48000); SNDRV_PCM_RATE_8000_48000);
runtime->hw.rate_min = 8000; runtime->hw.rate_min = 8000;
runtime->hw.rate_max = 48000; runtime->hw.rate_max = 48000;
use_src = true;
} else if (! ratep->rate) { } else if (! ratep->rate) {
int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC;
runtime->hw.rates = chip->ac97->rates[idx]; runtime->hw.rates = chip->ac97->rates[idx];
@ -1212,6 +1214,12 @@ static int snd_via82xx_pcm_open(struct via82xx *chip, struct viadev *viadev,
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err; return err;
if (use_src) {
err = snd_pcm_hw_rule_noresample(runtime, 48000);
if (err < 0)
return err;
}
runtime->private_data = viadev; runtime->private_data = viadev;
viadev->substream = substream; viadev->substream = substream;
@ -2068,8 +2076,9 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg);
if (chip->mpu_res) { if (chip->mpu_res) {
if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A, if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A,
mpu_port, MPU401_INFO_INTEGRATED, mpu_port, MPU401_INFO_INTEGRATED |
chip->irq, 0, &chip->rmidi) < 0) { MPU401_INFO_IRQ_HOOK, -1,
&chip->rmidi) < 0) {
printk(KERN_WARNING "unable to initialize MPU-401" printk(KERN_WARNING "unable to initialize MPU-401"
" at 0x%lx, skipping\n", mpu_port); " at 0x%lx, skipping\n", mpu_port);
legacy &= ~VIA_FUNC_ENABLE_MIDI; legacy &= ~VIA_FUNC_ENABLE_MIDI;

View File

@ -305,8 +305,9 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
if (chip->mpu_res) { if (chip->mpu_res) {
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI,
mpu_port[dev], mpu_port[dev],
MPU401_INFO_INTEGRATED, MPU401_INFO_INTEGRATED |
pci->irq, 0, &chip->rawmidi)) < 0) { MPU401_INFO_IRQ_HOOK,
-1, &chip->rawmidi)) < 0) {
printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]); printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]);
legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */ legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */
pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);

View File

@ -897,6 +897,18 @@ static int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream)
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ymfpci_pcm *ypcm; struct snd_ymfpci_pcm *ypcm;
int err;
runtime->hw = snd_ymfpci_playback;
/* FIXME? True value is 256/48 = 5.33333 ms */
err = snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
5334, UINT_MAX);
if (err < 0)
return err;
err = snd_pcm_hw_rule_noresample(runtime, 48000);
if (err < 0)
return err;
ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL); ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);
if (ypcm == NULL) if (ypcm == NULL)
@ -904,11 +916,8 @@ static int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream)
ypcm->chip = chip; ypcm->chip = chip;
ypcm->type = PLAYBACK_VOICE; ypcm->type = PLAYBACK_VOICE;
ypcm->substream = substream; ypcm->substream = substream;
runtime->hw = snd_ymfpci_playback;
runtime->private_data = ypcm; runtime->private_data = ypcm;
runtime->private_free = snd_ymfpci_pcm_free_substream; runtime->private_free = snd_ymfpci_pcm_free_substream;
/* FIXME? True value is 256/48 = 5.33333 ms */
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX);
return 0; return 0;
} }
@ -1013,6 +1022,18 @@ static int snd_ymfpci_capture_open(struct snd_pcm_substream *substream,
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ymfpci_pcm *ypcm; struct snd_ymfpci_pcm *ypcm;
int err;
runtime->hw = snd_ymfpci_capture;
/* FIXME? True value is 256/48 = 5.33333 ms */
err = snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
5334, UINT_MAX);
if (err < 0)
return err;
err = snd_pcm_hw_rule_noresample(runtime, 48000);
if (err < 0)
return err;
ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL); ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL);
if (ypcm == NULL) if (ypcm == NULL)
@ -1022,9 +1043,6 @@ static int snd_ymfpci_capture_open(struct snd_pcm_substream *substream,
ypcm->substream = substream; ypcm->substream = substream;
ypcm->capture_bank_number = capture_bank_number; ypcm->capture_bank_number = capture_bank_number;
chip->capture_substream[capture_bank_number] = substream; chip->capture_substream[capture_bank_number] = substream;
runtime->hw = snd_ymfpci_capture;
/* FIXME? True value is 256/48 = 5.33333 ms */
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 5333, UINT_MAX);
runtime->private_data = ypcm; runtime->private_data = ypcm;
runtime->private_free = snd_ymfpci_pcm_free_substream; runtime->private_free = snd_ymfpci_pcm_free_substream;
snd_ymfpci_hw_start(chip); snd_ymfpci_hw_start(chip);
@ -1615,7 +1633,7 @@ YMFPCI_DOUBLE("ADC Playback Volume", 0, YDSXGR_PRIADCOUTVOL),
YMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL), YMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL),
YMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL), YMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL),
YMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL), YMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL),
YMFPCI_DOUBLE("FM Legacy Volume", 0, YDSXGR_LEGACYOUTVOL), YMFPCI_DOUBLE("FM Legacy Playback Volume", 0, YDSXGR_LEGACYOUTVOL),
YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL), YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL),
YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL), YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL),
YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL), YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL),

View File

@ -82,7 +82,6 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
static int keywest_remove(struct i2c_client *client) static int keywest_remove(struct i2c_client *client)
{ {
i2c_set_clientdata(client, NULL);
if (! keywest_ctx) if (! keywest_ctx)
return 0; return 0;
if (client == keywest_ctx->client) if (client == keywest_ctx->client)

View File

@ -16,6 +16,7 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/bitrev.h> #include <linux/bitrev.h>
#include <linux/kernel.h>
#include "firmware.h" #include "firmware.h"
#include "chip.h" #include "chip.h"
@ -59,21 +60,19 @@ struct ihex_record {
unsigned int txt_offset; /* current position in txt_data */ unsigned int txt_offset; /* current position in txt_data */
}; };
static u8 usb6fire_fw_ihex_nibble(const u8 n)
{
if (n >= '0' && n <= '9')
return n - '0';
else if (n >= 'A' && n <= 'F')
return n - ('A' - 10);
else if (n >= 'a' && n <= 'f')
return n - ('a' - 10);
return 0;
}
static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc) static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc)
{ {
u8 val = (usb6fire_fw_ihex_nibble(data[0]) << 4) | u8 val = 0;
usb6fire_fw_ihex_nibble(data[1]); int hval;
hval = hex_to_bin(data[0]);
if (hval >= 0)
val |= (hval << 4);
hval = hex_to_bin(data[1]);
if (hval >= 0)
val |= hval;
*crc += val; *crc += val;
return val; return val;
} }

View File

@ -67,6 +67,7 @@ config SND_USB_CAIAQ
* Native Instruments Guitar Rig mobile * Native Instruments Guitar Rig mobile
* Native Instruments Traktor Kontrol X1 * Native Instruments Traktor Kontrol X1
* Native Instruments Traktor Kontrol S4 * Native Instruments Traktor Kontrol S4
* Native Instruments Maschine Controller
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called snd-usb-caiaq. will be called snd-usb-caiaq.
@ -85,6 +86,7 @@ config SND_USB_CAIAQ_INPUT
* Native Instruments Kore Controller 2 * Native Instruments Kore Controller 2
* Native Instruments Audio Kontrol 1 * Native Instruments Audio Kontrol 1
* Native Instruments Traktor Kontrol S4 * Native Instruments Traktor Kontrol S4
* Native Instruments Maschine Controller
config SND_USB_US122L config SND_USB_US122L
tristate "Tascam US-122L USB driver" tristate "Tascam US-122L USB driver"

View File

@ -3,16 +3,16 @@
# #
snd-usb-audio-objs := card.o \ snd-usb-audio-objs := card.o \
clock.o \
endpoint.o \
format.o \
helper.o \
mixer.o \ mixer.o \
mixer_quirks.o \ mixer_quirks.o \
pcm.o \
proc.o \ proc.o \
quirks.o \ quirks.o \
format.o \ stream.o
endpoint.o \
urb.o \
pcm.o \
helper.o \
clock.o
snd-usbmidi-lib-objs := midi.o snd-usbmidi-lib-objs := midi.o

View File

@ -50,7 +50,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, Session I/O}," "{Native Instruments, Session I/O},"
"{Native Instruments, GuitarRig mobile}" "{Native Instruments, GuitarRig mobile}"
"{Native Instruments, Traktor Kontrol X1}" "{Native Instruments, Traktor Kontrol X1}"
"{Native Instruments, Traktor Kontrol S4}"); "{Native Instruments, Traktor Kontrol S4}"
"{Native Instruments, Maschine Controller}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@ -146,6 +147,11 @@ static struct usb_device_id snd_usb_id_table[] = {
.idVendor = USB_VID_NATIVEINSTRUMENTS, .idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_TRAKTORAUDIO2 .idProduct = USB_PID_TRAKTORAUDIO2
}, },
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_MASCHINECONTROLLER
},
{ /* terminator */ } { /* terminator */ }
}; };

View File

@ -18,6 +18,7 @@
#define USB_PID_TRAKTORKONTROLX1 0x2305 #define USB_PID_TRAKTORKONTROLX1 0x2305
#define USB_PID_TRAKTORKONTROLS4 0xbaff #define USB_PID_TRAKTORKONTROLS4 0xbaff
#define USB_PID_TRAKTORAUDIO2 0x041d #define USB_PID_TRAKTORAUDIO2 0x041d
#define USB_PID_MASCHINECONTROLLER 0x0808
#define EP1_BUFSIZE 64 #define EP1_BUFSIZE 64
#define EP4_BUFSIZE 512 #define EP4_BUFSIZE 512

View File

@ -67,6 +67,61 @@ static unsigned short keycode_kore[] = {
KEY_BRL_DOT5 KEY_BRL_DOT5
}; };
#define MASCHINE_BUTTONS (42)
#define MASCHINE_BUTTON(X) ((X) + BTN_MISC)
#define MASCHINE_PADS (16)
#define MASCHINE_PAD(X) ((X) + ABS_PRESSURE)
static unsigned short keycode_maschine[] = {
MASCHINE_BUTTON(40), /* mute */
MASCHINE_BUTTON(39), /* solo */
MASCHINE_BUTTON(38), /* select */
MASCHINE_BUTTON(37), /* duplicate */
MASCHINE_BUTTON(36), /* navigate */
MASCHINE_BUTTON(35), /* pad mode */
MASCHINE_BUTTON(34), /* pattern */
MASCHINE_BUTTON(33), /* scene */
KEY_RESERVED, /* spacer */
MASCHINE_BUTTON(30), /* rec */
MASCHINE_BUTTON(31), /* erase */
MASCHINE_BUTTON(32), /* shift */
MASCHINE_BUTTON(28), /* grid */
MASCHINE_BUTTON(27), /* > */
MASCHINE_BUTTON(26), /* < */
MASCHINE_BUTTON(25), /* restart */
MASCHINE_BUTTON(21), /* E */
MASCHINE_BUTTON(22), /* F */
MASCHINE_BUTTON(23), /* G */
MASCHINE_BUTTON(24), /* H */
MASCHINE_BUTTON(20), /* D */
MASCHINE_BUTTON(19), /* C */
MASCHINE_BUTTON(18), /* B */
MASCHINE_BUTTON(17), /* A */
MASCHINE_BUTTON(0), /* control */
MASCHINE_BUTTON(2), /* browse */
MASCHINE_BUTTON(4), /* < */
MASCHINE_BUTTON(6), /* snap */
MASCHINE_BUTTON(7), /* autowrite */
MASCHINE_BUTTON(5), /* > */
MASCHINE_BUTTON(3), /* sampling */
MASCHINE_BUTTON(1), /* step */
MASCHINE_BUTTON(15), /* 8 softkeys */
MASCHINE_BUTTON(14),
MASCHINE_BUTTON(13),
MASCHINE_BUTTON(12),
MASCHINE_BUTTON(11),
MASCHINE_BUTTON(10),
MASCHINE_BUTTON(9),
MASCHINE_BUTTON(8),
MASCHINE_BUTTON(16), /* note repeat */
MASCHINE_BUTTON(29) /* play */
};
#define KONTROLX1_INPUTS (40) #define KONTROLX1_INPUTS (40)
#define KONTROLS4_BUTTONS (12 * 8) #define KONTROLS4_BUTTONS (12 * 8)
#define KONTROLS4_AXIS (46) #define KONTROLS4_AXIS (46)
@ -218,6 +273,29 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
input_report_abs(input_dev, ABS_HAT3Y, i); input_report_abs(input_dev, ABS_HAT3Y, i);
input_sync(input_dev); input_sync(input_dev);
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
/* 4 under the left screen */
input_report_abs(input_dev, ABS_HAT0X, decode_erp(buf[21], buf[20]));
input_report_abs(input_dev, ABS_HAT0Y, decode_erp(buf[15], buf[14]));
input_report_abs(input_dev, ABS_HAT1X, decode_erp(buf[9], buf[8]));
input_report_abs(input_dev, ABS_HAT1Y, decode_erp(buf[3], buf[2]));
/* 4 under the right screen */
input_report_abs(input_dev, ABS_HAT2X, decode_erp(buf[19], buf[18]));
input_report_abs(input_dev, ABS_HAT2Y, decode_erp(buf[13], buf[12]));
input_report_abs(input_dev, ABS_HAT3X, decode_erp(buf[7], buf[6]));
input_report_abs(input_dev, ABS_HAT3Y, decode_erp(buf[1], buf[0]));
/* volume */
input_report_abs(input_dev, ABS_RX, decode_erp(buf[17], buf[16]));
/* tempo */
input_report_abs(input_dev, ABS_RY, decode_erp(buf[11], buf[10]));
/* swing */
input_report_abs(input_dev, ABS_RZ, decode_erp(buf[5], buf[4]));
input_sync(input_dev);
break;
} }
} }
@ -400,6 +478,25 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
input_sync(dev->input_dev); input_sync(dev->input_dev);
} }
#define MASCHINE_MSGBLOCK_SIZE 2
static void snd_usb_caiaq_maschine_dispatch(struct snd_usb_caiaqdev *dev,
const unsigned char *buf,
unsigned int len)
{
unsigned int i, pad_id;
uint16_t pressure;
for (i = 0; i < MASCHINE_PADS; i++) {
pressure = be16_to_cpu(buf[i * 2] << 8 | buf[(i * 2) + 1]);
pad_id = pressure >> 12;
input_report_abs(dev->input_dev, MASCHINE_PAD(pad_id), pressure & 0xfff);
}
input_sync(dev->input_dev);
}
static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
{ {
struct snd_usb_caiaqdev *dev = urb->context; struct snd_usb_caiaqdev *dev = urb->context;
@ -425,6 +522,13 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length); snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length);
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
if (urb->actual_length < (MASCHINE_PADS * MASCHINE_MSGBLOCK_SIZE))
goto requeue;
snd_usb_caiaq_maschine_dispatch(dev, buf, urb->actual_length);
break;
} }
requeue: requeue:
@ -444,6 +548,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev)
switch (dev->chip.usb_id) { switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
return -EIO; return -EIO;
break; break;
@ -462,6 +567,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev)
switch (dev->chip.usb_id) { switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
usb_kill_urb(dev->ep4_in_urb); usb_kill_urb(dev->ep4_in_urb);
break; break;
} }
@ -652,6 +758,50 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) |
BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) |
BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) |
BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) |
BIT_MASK(ABS_RX) | BIT_MASK(ABS_RY) |
BIT_MASK(ABS_RZ);
BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_maschine));
memcpy(dev->keycode, keycode_maschine, sizeof(keycode_maschine));
input->keycodemax = ARRAY_SIZE(keycode_maschine);
for (i = 0; i < MASCHINE_PADS; i++) {
input->absbit[0] |= MASCHINE_PAD(i);
input_set_abs_params(input, MASCHINE_PAD(i), 0, 0xfff, 5, 10);
}
input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10);
input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10);
input_set_abs_params(input, ABS_HAT1X, 0, 999, 0, 10);
input_set_abs_params(input, ABS_HAT1Y, 0, 999, 0, 10);
input_set_abs_params(input, ABS_HAT2X, 0, 999, 0, 10);
input_set_abs_params(input, ABS_HAT2Y, 0, 999, 0, 10);
input_set_abs_params(input, ABS_HAT3X, 0, 999, 0, 10);
input_set_abs_params(input, ABS_HAT3Y, 0, 999, 0, 10);
input_set_abs_params(input, ABS_RX, 0, 999, 0, 10);
input_set_abs_params(input, ABS_RY, 0, 999, 0, 10);
input_set_abs_params(input, ABS_RZ, 0, 999, 0, 10);
dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->ep4_in_urb) {
ret = -ENOMEM;
goto exit_free_idev;
}
usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 0x4),
dev->ep4_in_buf, EP4_BUFSIZE,
snd_usb_caiaq_ep4_reply_dispatch, dev);
snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
break;
default: default:
/* no input methods supported on this device */ /* no input methods supported on this device */
goto exit_free_idev; goto exit_free_idev;
@ -664,15 +814,17 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
for (i = 0; i < input->keycodemax; i++) for (i = 0; i < input->keycodemax; i++)
__set_bit(dev->keycode[i], input->keybit); __set_bit(dev->keycode[i], input->keybit);
dev->input_dev = input;
ret = input_register_device(input); ret = input_register_device(input);
if (ret < 0) if (ret < 0)
goto exit_free_idev; goto exit_free_idev;
dev->input_dev = input;
return 0; return 0;
exit_free_idev: exit_free_idev:
input_free_device(input); input_free_device(input);
dev->input_dev = NULL;
return ret; return ret;
} }
@ -688,4 +840,3 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
input_unregister_device(dev->input_dev); input_unregister_device(dev->input_dev);
dev->input_dev = NULL; dev->input_dev = NULL;
} }

View File

@ -65,9 +65,9 @@
#include "helper.h" #include "helper.h"
#include "debug.h" #include "debug.h"
#include "pcm.h" #include "pcm.h"
#include "urb.h"
#include "format.h" #include "format.h"
#include "power.h" #include "power.h"
#include "stream.h"
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("USB Audio"); MODULE_DESCRIPTION("USB Audio");
@ -185,7 +185,7 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
return -EINVAL; return -EINVAL;
} }
if (! snd_usb_parse_audio_endpoints(chip, interface)) { if (! snd_usb_parse_audio_interface(chip, interface)) {
usb_set_interface(dev, interface, 0); /* reset the current interface */ usb_set_interface(dev, interface, 0); /* reset the current interface */
usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
return -EINVAL; return -EINVAL;

View File

@ -94,6 +94,8 @@ struct snd_usb_substream {
spinlock_t lock; spinlock_t lock;
struct snd_urb_ops ops; /* callbacks (must be filled at init) */ struct snd_urb_ops ops; /* callbacks (must be filled at init) */
int last_frame_number; /* stored frame number */
int last_delay; /* stored delay */
}; };
struct snd_usb_stream { struct snd_usb_stream {

View File

@ -91,7 +91,7 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
UAC2_CX_CLOCK_SELECTOR << 8, UAC2_CX_CLOCK_SELECTOR << 8,
snd_usb_ctrl_intf(chip) | (selector_id << 8), snd_usb_ctrl_intf(chip) | (selector_id << 8),
&buf, sizeof(buf), 1000); &buf, sizeof(buf));
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -118,7 +118,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_CLOCK_VALID << 8, UAC2_CS_CONTROL_CLOCK_VALID << 8,
snd_usb_ctrl_intf(chip) | (source_id << 8), snd_usb_ctrl_intf(chip) | (source_id << 8),
&data, sizeof(data), 1000); &data, sizeof(data));
if (err < 0) { if (err < 0) {
snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
@ -222,7 +222,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
data, sizeof(data), 1000)) < 0) { data, sizeof(data))) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
dev->devnum, iface, fmt->altsetting, rate, ep); dev->devnum, iface, fmt->altsetting, rate, ep);
return err; return err;
@ -231,7 +231,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
data, sizeof(data), 1000)) < 0) { data, sizeof(data))) < 0) {
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
dev->devnum, iface, fmt->altsetting, ep); dev->devnum, iface, fmt->altsetting, ep);
return 0; /* some devices don't support reading */ return 0; /* some devices don't support reading */
@ -273,7 +273,7 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
UAC2_CS_CONTROL_SAM_FREQ << 8, UAC2_CS_CONTROL_SAM_FREQ << 8,
snd_usb_ctrl_intf(chip) | (clock << 8), snd_usb_ctrl_intf(chip) | (clock << 8),
data, sizeof(data), 1000)) < 0) { data, sizeof(data))) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
dev->devnum, iface, fmt->altsetting, rate); dev->devnum, iface, fmt->altsetting, rate);
return err; return err;
@ -283,7 +283,7 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_SAM_FREQ << 8, UAC2_CS_CONTROL_SAM_FREQ << 8,
snd_usb_ctrl_intf(chip) | (clock << 8), snd_usb_ctrl_intf(chip) | (clock << 8),
data, sizeof(data), 1000)) < 0) { data, sizeof(data))) < 0) {
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
dev->devnum, iface, fmt->altsetting); dev->devnum, iface, fmt->altsetting);
return err; return err;

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,21 @@
#ifndef __USBAUDIO_ENDPOINT_H #ifndef __USBAUDIO_ENDPOINT_H
#define __USBAUDIO_ENDPOINT_H #define __USBAUDIO_ENDPOINT_H
int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, void snd_usb_init_substream(struct snd_usb_stream *as,
int iface_no); int stream,
struct audioformat *fp);
int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
int stream, unsigned int period_bytes,
struct audioformat *fp); unsigned int rate,
unsigned int frame_bits);
void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
int snd_usb_substream_prepare(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime);
int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
#endif /* __USBAUDIO_ENDPOINT_H */ #endif /* __USBAUDIO_ENDPOINT_H */

View File

@ -286,7 +286,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_SAM_FREQ << 8, UAC2_CS_CONTROL_SAM_FREQ << 8,
snd_usb_ctrl_intf(chip) | (clock << 8), snd_usb_ctrl_intf(chip) | (clock << 8),
tmp, sizeof(tmp), 1000); tmp, sizeof(tmp));
if (ret < 0) { if (ret < 0) {
snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n", snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n",
@ -307,7 +307,7 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_SAM_FREQ << 8, UAC2_CS_CONTROL_SAM_FREQ << 8,
snd_usb_ctrl_intf(chip) | (clock << 8), snd_usb_ctrl_intf(chip) | (clock << 8),
data, data_size, 1000); data, data_size);
if (ret < 0) { if (ret < 0) {
snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n", snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n",

View File

@ -81,7 +81,7 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype
*/ */
int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8 requesttype, __u16 value, __u16 index, void *data, __u8 requesttype, __u16 value, __u16 index, void *data,
__u16 size, int timeout) __u16 size)
{ {
int err; int err;
void *buf = NULL; void *buf = NULL;
@ -92,7 +92,7 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
return -ENOMEM; return -ENOMEM;
} }
err = usb_control_msg(dev, pipe, request, requesttype, err = usb_control_msg(dev, pipe, request, requesttype,
value, index, buf, size, timeout); value, index, buf, size, 1000);
if (size > 0) { if (size > 0) {
memcpy(data, buf, size); memcpy(data, buf, size);
kfree(buf); kfree(buf);

View File

@ -8,7 +8,7 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub
int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value, __u16 index, __u8 request, __u8 requesttype, __u16 value, __u16 index,
void *data, __u16 size, int timeout); void *data, __u16 size);
unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
struct usb_host_interface *alts); struct usb_host_interface *alts);

View File

@ -816,6 +816,22 @@ static struct usb_protocol_ops snd_usbmidi_raw_ops = {
.output = snd_usbmidi_raw_output, .output = snd_usbmidi_raw_output,
}; };
/*
* FTDI protocol: raw MIDI bytes, but input packets have two modem status bytes.
*/
static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint* ep,
uint8_t* buffer, int buffer_length)
{
if (buffer_length > 2)
snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2);
}
static struct usb_protocol_ops snd_usbmidi_ftdi_ops = {
.input = snd_usbmidi_ftdi_input,
.output = snd_usbmidi_raw_output,
};
static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep, static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep,
uint8_t *buffer, int buffer_length) uint8_t *buffer, int buffer_length)
{ {
@ -2163,6 +2179,17 @@ int snd_usbmidi_create(struct snd_card *card,
/* endpoint 1 is input-only */ /* endpoint 1 is input-only */
endpoints[1].out_cables = 0; endpoints[1].out_cables = 0;
break; break;
case QUIRK_MIDI_FTDI:
umidi->usb_protocol_ops = &snd_usbmidi_ftdi_ops;
/* set baud rate to 31250 (48 MHz / 16 / 96) */
err = usb_control_msg(umidi->dev, usb_sndctrlpipe(umidi->dev, 0),
3, 0x40, 0x60, 0, NULL, 0, 1000);
if (err < 0)
break;
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
default: default:
snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
err = -ENXIO; err = -ENXIO;

View File

@ -296,7 +296,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, val_len, 100) >= val_len) { buf, val_len) >= val_len) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len)); *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
snd_usb_autosuspend(cval->mixer->chip); snd_usb_autosuspend(cval->mixer->chip);
return 0; return 0;
@ -333,7 +333,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, size, 1000); buf, size);
snd_usb_autosuspend(chip); snd_usb_autosuspend(chip);
if (ret < 0) { if (ret < 0) {
@ -445,7 +445,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
usb_sndctrlpipe(chip->dev, 0), request, usb_sndctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, val_len, 100) >= 0) { buf, val_len) >= 0) {
snd_usb_autosuspend(chip); snd_usb_autosuspend(chip);
return 0; return 0;
} }
@ -881,8 +881,17 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1; uinfo->value.integer.max = 1;
} else { } else {
if (! cval->initialized) if (!cval->initialized) {
get_min_max(cval, 0); get_min_max(cval, 0);
if (cval->initialized && cval->dBmin >= cval->dBmax) {
kcontrol->vd[0].access &=
~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
snd_ctl_notify(cval->mixer->chip->card,
SNDRV_CTL_EVENT_MASK_INFO,
&kcontrol->id);
}
}
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
uinfo->value.integer.max = uinfo->value.integer.max =
(cval->max - cval->min + cval->res - 1) / cval->res; (cval->max - cval->min + cval->res - 1) / cval->res;
@ -1250,7 +1259,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, 0); build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, 0);
} }
} else { /* UAC_VERSION_2 */ } else { /* UAC_VERSION_2 */
for (i = 0; i < 30/2; i++) { for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) {
unsigned int ch_bits = 0; unsigned int ch_bits = 0;
unsigned int ch_read_only = 0; unsigned int ch_read_only = 0;

View File

@ -190,18 +190,18 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
err = snd_usb_ctl_msg(mixer->chip->dev, err = snd_usb_ctl_msg(mixer->chip->dev,
usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
!value, 0, NULL, 0, 100); !value, 0, NULL, 0);
/* USB X-Fi S51 Pro */ /* USB X-Fi S51 Pro */
if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df))
err = snd_usb_ctl_msg(mixer->chip->dev, err = snd_usb_ctl_msg(mixer->chip->dev,
usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
!value, 0, NULL, 0, 100); !value, 0, NULL, 0);
else else
err = snd_usb_ctl_msg(mixer->chip->dev, err = snd_usb_ctl_msg(mixer->chip->dev,
usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
value, index + 2, NULL, 0, 100); value, index + 2, NULL, 0);
if (err < 0) if (err < 0)
return err; return err;
mixer->audigy2nx_leds[index] = value; mixer->audigy2nx_leds[index] = value;
@ -299,7 +299,7 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
usb_rcvctrlpipe(mixer->chip->dev, 0), usb_rcvctrlpipe(mixer->chip->dev, 0),
UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE, 0, USB_RECIP_INTERFACE, 0,
jacks[i].unitid << 8, buf, 3, 100); jacks[i].unitid << 8, buf, 3);
if (err == 3 && (buf[0] == 3 || buf[0] == 6)) if (err == 3 && (buf[0] == 3 || buf[0] == 6))
snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);
else else
@ -332,7 +332,7 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
err = snd_usb_ctl_msg(mixer->chip->dev, err = snd_usb_ctl_msg(mixer->chip->dev,
usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
50, 0, &new_status, 1, 100); 50, 0, &new_status, 1);
if (err < 0) if (err < 0)
return err; return err;
mixer->xonar_u1_status = new_status; mixer->xonar_u1_status = new_status;

View File

@ -28,12 +28,36 @@
#include "card.h" #include "card.h"
#include "quirks.h" #include "quirks.h"
#include "debug.h" #include "debug.h"
#include "urb.h" #include "endpoint.h"
#include "helper.h" #include "helper.h"
#include "pcm.h" #include "pcm.h"
#include "clock.h" #include "clock.h"
#include "power.h" #include "power.h"
/* return the estimated delay based on USB frame counters */
snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
unsigned int rate)
{
int current_frame_number;
int frame_diff;
int est_delay;
current_frame_number = usb_get_current_frame_number(subs->dev);
/*
* HCD implementations use different widths, use lower 8 bits.
* The delay will be managed up to 256ms, which is more than
* enough
*/
frame_diff = (current_frame_number - subs->last_frame_number) & 0xff;
/* Approximation based on number of samples per USB frame (ms),
some truncation for 44.1 but the estimate is good enough */
est_delay = subs->last_delay - (frame_diff * rate / 1000);
if (est_delay < 0)
est_delay = 0;
return est_delay;
}
/* /*
* return the current pcm pointer. just based on the hwptr_done value. * return the current pcm pointer. just based on the hwptr_done value.
*/ */
@ -45,6 +69,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
subs = (struct snd_usb_substream *)substream->runtime->private_data; subs = (struct snd_usb_substream *)substream->runtime->private_data;
spin_lock(&subs->lock); spin_lock(&subs->lock);
hwptr_done = subs->hwptr_done; hwptr_done = subs->hwptr_done;
substream->runtime->delay = snd_usb_pcm_delay(subs,
substream->runtime->rate);
spin_unlock(&subs->lock); spin_unlock(&subs->lock);
return hwptr_done / (substream->runtime->frame_bits >> 3); return hwptr_done / (substream->runtime->frame_bits >> 3);
} }
@ -126,7 +152,7 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep,
data, sizeof(data), 1000)) < 0) { data, sizeof(data))) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
dev->devnum, iface, ep); dev->devnum, iface, ep);
return err; return err;
@ -150,7 +176,7 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
UAC2_EP_CS_PITCH << 8, 0, UAC2_EP_CS_PITCH << 8, 0,
data, sizeof(data), 1000)) < 0) { data, sizeof(data))) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n", snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n",
dev->devnum, iface, fmt->altsetting); dev->devnum, iface, fmt->altsetting);
return err; return err;
@ -417,6 +443,8 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
subs->hwptr_done = 0; subs->hwptr_done = 0;
subs->transfer_done = 0; subs->transfer_done = 0;
subs->phase = 0; subs->phase = 0;
subs->last_delay = 0;
subs->last_frame_number = 0;
runtime->delay = 0; runtime->delay = 0;
return snd_usb_substream_prepare(subs, runtime); return snd_usb_substream_prepare(subs, runtime);

View File

@ -1,6 +1,9 @@
#ifndef __USBAUDIO_PCM_H #ifndef __USBAUDIO_PCM_H
#define __USBAUDIO_PCM_H #define __USBAUDIO_PCM_H
snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
unsigned int rate);
void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);
int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,

View File

@ -39,6 +39,17 @@
.idProduct = prod, \ .idProduct = prod, \
.bInterfaceClass = USB_CLASS_VENDOR_SPEC .bInterfaceClass = USB_CLASS_VENDOR_SPEC
/* FTDI devices */
{
USB_DEVICE(0x0403, 0xb8d8),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
/* .vendor_name = "STARR LABS", */
/* .product_name = "Starr Labs MIDI USB device", */
.ifnum = 0,
.type = QUIRK_MIDI_FTDI
}
},
/* Creative/Toshiba Multimedia Center SB-0500 */ /* Creative/Toshiba Multimedia Center SB-0500 */
{ {
USB_DEVICE(0x041e, 0x3048), USB_DEVICE(0x041e, 0x3048),
@ -1677,6 +1688,20 @@ YAMAHA_DEVICE(0x7010, "UB99"),
} }
} }
}, },
{
/* Added support for Roland UM-ONE which differs from UM-1 */
USB_DEVICE(0x0582, 0x012a),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
/* .vendor_name = "ROLAND", */
/* .product_name = "UM-ONE", */
.ifnum = 0,
.type = QUIRK_MIDI_FIXED_ENDPOINT,
.data = & (const struct snd_usb_midi_endpoint_info) {
.out_cables = 0x0001,
.in_cables = 0x0003
}
}
},
{ {
USB_DEVICE(0x0582, 0x011e), USB_DEVICE(0x0582, 0x011e),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {

View File

@ -34,6 +34,7 @@
#include "endpoint.h" #include "endpoint.h"
#include "pcm.h" #include "pcm.h"
#include "clock.h" #include "clock.h"
#include "stream.h"
/* /*
* handle the quirks for the contained interfaces * handle the quirks for the contained interfaces
@ -106,7 +107,7 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
alts = &iface->altsetting[0]; alts = &iface->altsetting[0];
altsd = get_iface_desc(alts); altsd = get_iface_desc(alts);
err = snd_usb_parse_audio_endpoints(chip, altsd->bInterfaceNumber); err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
if (err < 0) { if (err < 0) {
snd_printk(KERN_ERR "cannot setup if %d: error %d\n", snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
altsd->bInterfaceNumber, err); altsd->bInterfaceNumber, err);
@ -147,7 +148,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
stream = (fp->endpoint & USB_DIR_IN) stream = (fp->endpoint & USB_DIR_IN)
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
err = snd_usb_add_audio_endpoint(chip, stream, fp); err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) { if (err < 0) {
kfree(fp); kfree(fp);
kfree(rate_table); kfree(rate_table);
@ -254,7 +255,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
stream = (fp->endpoint & USB_DIR_IN) stream = (fp->endpoint & USB_DIR_IN)
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
err = snd_usb_add_audio_endpoint(chip, stream, fp); err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) { if (err < 0) {
kfree(fp); kfree(fp);
return err; return err;
@ -306,6 +307,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
[QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_MIDI_CME] = create_any_midi_quirk,
[QUIRK_MIDI_AKAI] = create_any_midi_quirk, [QUIRK_MIDI_AKAI] = create_any_midi_quirk,
[QUIRK_MIDI_FTDI] = create_any_midi_quirk,
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
@ -338,7 +340,7 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
snd_printdd("sending Extigy boot sequence...\n"); snd_printdd("sending Extigy boot sequence...\n");
/* Send message to force it to reconnect with full interface. */ /* Send message to force it to reconnect with full interface. */
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0), err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
0x10, 0x43, 0x0001, 0x000a, NULL, 0, 1000); 0x10, 0x43, 0x0001, 0x000a, NULL, 0);
if (err < 0) snd_printdd("error sending boot message: %d\n", err); if (err < 0) snd_printdd("error sending boot message: %d\n", err);
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
&dev->descriptor, sizeof(dev->descriptor)); &dev->descriptor, sizeof(dev->descriptor));
@ -359,11 +361,11 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
0, 0, &buf, 1, 1000); 0, 0, &buf, 1);
if (buf == 0) { if (buf == 0) {
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
1, 2000, NULL, 0, 1000); 1, 2000, NULL, 0);
return -ENODEV; return -ENODEV;
} }
return 0; return 0;
@ -406,7 +408,7 @@ static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 valu
buf[3] = reg; buf[3] = reg;
return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
0, 0, &buf, 4, 1000); 0, 0, &buf, 4);
} }
static int snd_usb_cm106_boot_quirk(struct usb_device *dev) static int snd_usb_cm106_boot_quirk(struct usb_device *dev)

452
sound/usb/stream.c Normal file
View File

@ -0,0 +1,452 @@
/*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include "usbaudio.h"
#include "card.h"
#include "proc.h"
#include "quirks.h"
#include "endpoint.h"
#include "pcm.h"
#include "helper.h"
#include "format.h"
#include "clock.h"
#include "stream.h"
/*
* free a substream
*/
static void free_substream(struct snd_usb_substream *subs)
{
struct list_head *p, *n;
if (!subs->num_formats)
return; /* not initialized */
list_for_each_safe(p, n, &subs->fmt_list) {
struct audioformat *fp = list_entry(p, struct audioformat, list);
kfree(fp->rate_table);
kfree(fp);
}
kfree(subs->rate_list.list);
}
/*
* free a usb stream instance
*/
static void snd_usb_audio_stream_free(struct snd_usb_stream *stream)
{
free_substream(&stream->substream[0]);
free_substream(&stream->substream[1]);
list_del(&stream->list);
kfree(stream);
}
static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
{
struct snd_usb_stream *stream = pcm->private_data;
if (stream) {
stream->pcm = NULL;
snd_usb_audio_stream_free(stream);
}
}
/*
* add this endpoint to the chip instance.
* if a stream with the same endpoint already exists, append to it.
* if not, create a new pcm stream.
*/
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
int stream,
struct audioformat *fp)
{
struct list_head *p;
struct snd_usb_stream *as;
struct snd_usb_substream *subs;
struct snd_pcm *pcm;
int err;
list_for_each(p, &chip->pcm_list) {
as = list_entry(p, struct snd_usb_stream, list);
if (as->fmt_type != fp->fmt_type)
continue;
subs = &as->substream[stream];
if (!subs->endpoint)
continue;
if (subs->endpoint == fp->endpoint) {
list_add_tail(&fp->list, &subs->fmt_list);
subs->num_formats++;
subs->formats |= fp->formats;
return 0;
}
}
/* look for an empty stream */
list_for_each(p, &chip->pcm_list) {
as = list_entry(p, struct snd_usb_stream, list);
if (as->fmt_type != fp->fmt_type)
continue;
subs = &as->substream[stream];
if (subs->endpoint)
continue;
err = snd_pcm_new_stream(as->pcm, stream, 1);
if (err < 0)
return err;
snd_usb_init_substream(as, stream, fp);
return 0;
}
/* create a new pcm */
as = kzalloc(sizeof(*as), GFP_KERNEL);
if (!as)
return -ENOMEM;
as->pcm_index = chip->pcm_devs;
as->chip = chip;
as->fmt_type = fp->fmt_type;
err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
&pcm);
if (err < 0) {
kfree(as);
return err;
}
as->pcm = pcm;
pcm->private_data = as;
pcm->private_free = snd_usb_audio_pcm_free;
pcm->info_flags = 0;
if (chip->pcm_devs > 0)
sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs);
else
strcpy(pcm->name, "USB Audio");
snd_usb_init_substream(as, stream, fp);
list_add(&as->list, &chip->pcm_list);
chip->pcm_devs++;
snd_usb_proc_pcm_format_add(as);
return 0;
}
static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
struct usb_host_interface *alts,
int protocol, int iface_no)
{
/* parsed with a v1 header here. that's ok as we only look at the
* header first which is the same for both versions */
struct uac_iso_endpoint_descriptor *csep;
struct usb_interface_descriptor *altsd = get_iface_desc(alts);
int attributes = 0;
csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
/* Creamware Noah has this descriptor after the 2nd endpoint */
if (!csep && altsd->bNumEndpoints >= 2)
csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
if (!csep || csep->bLength < 7 ||
csep->bDescriptorSubtype != UAC_EP_GENERAL) {
snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
" class specific endpoint descriptor\n",
chip->dev->devnum, iface_no,
altsd->bAlternateSetting);
return 0;
}
if (protocol == UAC_VERSION_1) {
attributes = csep->bmAttributes;
} else {
struct uac2_iso_endpoint_descriptor *csep2 =
(struct uac2_iso_endpoint_descriptor *) csep;
attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX;
/* emulate the endpoint attributes of a v1 device */
if (csep2->bmControls & UAC2_CONTROL_PITCH)
attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
}
return attributes;
}
static struct uac2_input_terminal_descriptor *
snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
int terminal_id)
{
struct uac2_input_terminal_descriptor *term = NULL;
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
term, UAC_INPUT_TERMINAL))) {
if (term->bTerminalID == terminal_id)
return term;
}
return NULL;
}
static struct uac2_output_terminal_descriptor *
snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
int terminal_id)
{
struct uac2_output_terminal_descriptor *term = NULL;
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
term, UAC_OUTPUT_TERMINAL))) {
if (term->bTerminalID == terminal_id)
return term;
}
return NULL;
}
int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
{
struct usb_device *dev;
struct usb_interface *iface;
struct usb_host_interface *alts;
struct usb_interface_descriptor *altsd;
int i, altno, err, stream;
int format = 0, num_channels = 0;
struct audioformat *fp = NULL;
int num, protocol, clock = 0;
struct uac_format_type_i_continuous_descriptor *fmt;
dev = chip->dev;
/* parse the interface's altsettings */
iface = usb_ifnum_to_if(dev, iface_no);
num = iface->num_altsetting;
/*
* Dallas DS4201 workaround: It presents 5 altsettings, but the last
* one misses syncpipe, and does not produce any sound.
*/
if (chip->usb_id == USB_ID(0x04fa, 0x4201))
num = 4;
for (i = 0; i < num; i++) {
alts = &iface->altsetting[i];
altsd = get_iface_desc(alts);
protocol = altsd->bInterfaceProtocol;
/* skip invalid one */
if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
(altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
altsd->bNumEndpoints < 1 ||
le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
continue;
/* must be isochronous */
if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC)
continue;
/* check direction */
stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
altno = altsd->bAlternateSetting;
if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
continue;
/* get audio formats */
switch (protocol) {
default:
snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n",
dev->devnum, iface_no, altno, protocol);
protocol = UAC_VERSION_1;
/* fall through */
case UAC_VERSION_1: {
struct uac1_as_header_descriptor *as =
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
if (!as) {
snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
dev->devnum, iface_no, altno);
continue;
}
if (as->bLength < sizeof(*as)) {
snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
dev->devnum, iface_no, altno);
continue;
}
format = le16_to_cpu(as->wFormatTag); /* remember the format value */
break;
}
case UAC_VERSION_2: {
struct uac2_input_terminal_descriptor *input_term;
struct uac2_output_terminal_descriptor *output_term;
struct uac2_as_header_descriptor *as =
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
if (!as) {
snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
dev->devnum, iface_no, altno);
continue;
}
if (as->bLength < sizeof(*as)) {
snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
dev->devnum, iface_no, altno);
continue;
}
num_channels = as->bNrChannels;
format = le32_to_cpu(as->bmFormats);
/* lookup the terminal associated to this interface
* to extract the clock */
input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink);
if (input_term) {
clock = input_term->bCSourceID;
break;
}
output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink);
if (output_term) {
clock = output_term->bCSourceID;
break;
}
snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n",
dev->devnum, iface_no, altno, as->bTerminalLink);
continue;
}
}
/* get format type */
fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE);
if (!fmt) {
snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n",
dev->devnum, iface_no, altno);
continue;
}
if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) {
snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
dev->devnum, iface_no, altno);
continue;
}
/*
* Blue Microphones workaround: The last altsetting is identical
* with the previous one, except for a larger packet size, but
* is actually a mislabeled two-channel setting; ignore it.
*/
if (fmt->bNrChannels == 1 &&
fmt->bSubframeSize == 2 &&
altno == 2 && num == 3 &&
fp && fp->altsetting == 1 && fp->channels == 1 &&
fp->formats == SNDRV_PCM_FMTBIT_S16_LE &&
protocol == UAC_VERSION_1 &&
le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) ==
fp->maxpacksize * 2)
continue;
fp = kzalloc(sizeof(*fp), GFP_KERNEL);
if (! fp) {
snd_printk(KERN_ERR "cannot malloc\n");
return -ENOMEM;
}
fp->iface = iface_no;
fp->altsetting = altno;
fp->altset_idx = i;
fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
fp->datainterval = snd_usb_parse_datainterval(chip, alts);
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
/* num_channels is only set for v2 interfaces */
fp->channels = num_channels;
if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
* (fp->maxpacksize & 0x7ff);
fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
fp->clock = clock;
/* some quirks for attributes here */
switch (chip->usb_id) {
case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
/* Optoplay sets the sample rate attribute although
* it seems not supporting it in fact.
*/
fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
break;
case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
/* doesn't set the sample rate attribute, but supports it */
fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
break;
case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */
case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */
case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
an older model 77d:223) */
/*
* plantronics headset and Griffin iMic have set adaptive-in
* although it's really not...
*/
fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
else
fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
break;
}
/* ok, let's parse further... */
if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
kfree(fp->rate_table);
kfree(fp);
fp = NULL;
continue;
}
snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) {
kfree(fp->rate_table);
kfree(fp);
return err;
}
/* try to set the interface... */
usb_set_interface(chip->dev, iface_no, altno);
snd_usb_init_pitch(chip, iface_no, alts, fp);
snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max);
}
return 0;
}

12
sound/usb/stream.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __USBAUDIO_STREAM_H
#define __USBAUDIO_STREAM_H
int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
int iface_no);
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
int stream,
struct audioformat *fp);
#endif /* __USBAUDIO_STREAM_H */

View File

@ -1,941 +0,0 @@
/*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include "usbaudio.h"
#include "helper.h"
#include "card.h"
#include "urb.h"
#include "pcm.h"
/*
* convert a sampling rate into our full speed format (fs/1000 in Q16.16)
* this will overflow at approx 524 kHz
*/
static inline unsigned get_usb_full_speed_rate(unsigned int rate)
{
return ((rate << 13) + 62) / 125;
}
/*
* convert a sampling rate into USB high speed format (fs/8000 in Q16.16)
* this will overflow at approx 4 MHz
*/
static inline unsigned get_usb_high_speed_rate(unsigned int rate)
{
return ((rate << 10) + 62) / 125;
}
/*
* unlink active urbs.
*/
static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep)
{
struct snd_usb_audio *chip = subs->stream->chip;
unsigned int i;
int async;
subs->running = 0;
if (!force && subs->stream->chip->shutdown) /* to be sure... */
return -EBADFD;
async = !can_sleep && chip->async_unlink;
if (!async && in_interrupt())
return 0;
for (i = 0; i < subs->nurbs; i++) {
if (test_bit(i, &subs->active_mask)) {
if (!test_and_set_bit(i, &subs->unlink_mask)) {
struct urb *u = subs->dataurb[i].urb;
if (async)
usb_unlink_urb(u);
else
usb_kill_urb(u);
}
}
}
if (subs->syncpipe) {
for (i = 0; i < SYNC_URBS; i++) {
if (test_bit(i+16, &subs->active_mask)) {
if (!test_and_set_bit(i+16, &subs->unlink_mask)) {
struct urb *u = subs->syncurb[i].urb;
if (async)
usb_unlink_urb(u);
else
usb_kill_urb(u);
}
}
}
}
return 0;
}
/*
* release a urb data
*/
static void release_urb_ctx(struct snd_urb_ctx *u)
{
if (u->urb) {
if (u->buffer_size)
usb_free_coherent(u->subs->dev, u->buffer_size,
u->urb->transfer_buffer,
u->urb->transfer_dma);
usb_free_urb(u->urb);
u->urb = NULL;
}
}
/*
* wait until all urbs are processed.
*/
static int wait_clear_urbs(struct snd_usb_substream *subs)
{
unsigned long end_time = jiffies + msecs_to_jiffies(1000);
unsigned int i;
int alive;
do {
alive = 0;
for (i = 0; i < subs->nurbs; i++) {
if (test_bit(i, &subs->active_mask))
alive++;
}
if (subs->syncpipe) {
for (i = 0; i < SYNC_URBS; i++) {
if (test_bit(i + 16, &subs->active_mask))
alive++;
}
}
if (! alive)
break;
schedule_timeout_uninterruptible(1);
} while (time_before(jiffies, end_time));
if (alive)
snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
return 0;
}
/*
* release a substream
*/
void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
{
int i;
/* stop urbs (to be sure) */
deactivate_urbs(subs, force, 1);
wait_clear_urbs(subs);
for (i = 0; i < MAX_URBS; i++)
release_urb_ctx(&subs->dataurb[i]);
for (i = 0; i < SYNC_URBS; i++)
release_urb_ctx(&subs->syncurb[i]);
usb_free_coherent(subs->dev, SYNC_URBS * 4,
subs->syncbuf, subs->sync_dma);
subs->syncbuf = NULL;
subs->nurbs = 0;
}
/*
* complete callback from data urb
*/
static void snd_complete_urb(struct urb *urb)
{
struct snd_urb_ctx *ctx = urb->context;
struct snd_usb_substream *subs = ctx->subs;
struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
int err = 0;
if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
!subs->running || /* can be stopped during retire callback */
(err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
(err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
clear_bit(ctx->index, &subs->active_mask);
if (err < 0) {
snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
}
}
}
/*
* complete callback from sync urb
*/
static void snd_complete_sync_urb(struct urb *urb)
{
struct snd_urb_ctx *ctx = urb->context;
struct snd_usb_substream *subs = ctx->subs;
struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
int err = 0;
if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) ||
!subs->running || /* can be stopped during retire callback */
(err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 ||
(err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
clear_bit(ctx->index + 16, &subs->active_mask);
if (err < 0) {
snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err);
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
}
}
}
/*
* initialize a substream for plaback/capture
*/
int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
unsigned int period_bytes,
unsigned int rate,
unsigned int frame_bits)
{
unsigned int maxsize, i;
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int urb_packs, total_packs, packs_per_ms;
struct snd_usb_audio *chip = subs->stream->chip;
/* calculate the frequency in 16.16 format */
if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
subs->freqn = get_usb_full_speed_rate(rate);
else
subs->freqn = get_usb_high_speed_rate(rate);
subs->freqm = subs->freqn;
subs->freqshift = INT_MIN;
/* calculate max. frequency */
if (subs->maxpacksize) {
/* whatever fits into a max. size packet */
maxsize = subs->maxpacksize;
subs->freqmax = (maxsize / (frame_bits >> 3))
<< (16 - subs->datainterval);
} else {
/* no max. packet size: just take 25% higher than nominal */
subs->freqmax = subs->freqn + (subs->freqn >> 2);
maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
>> (16 - subs->datainterval);
}
subs->phase = 0;
if (subs->fill_max)
subs->curpacksize = subs->maxpacksize;
else
subs->curpacksize = maxsize;
if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
packs_per_ms = 8 >> subs->datainterval;
else
packs_per_ms = 1;
if (is_playback) {
urb_packs = max(chip->nrpacks, 1);
urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
} else
urb_packs = 1;
urb_packs *= packs_per_ms;
if (subs->syncpipe)
urb_packs = min(urb_packs, 1U << subs->syncinterval);
/* decide how many packets to be used */
if (is_playback) {
unsigned int minsize, maxpacks;
/* determine how small a packet can be */
minsize = (subs->freqn >> (16 - subs->datainterval))
* (frame_bits >> 3);
/* with sync from device, assume it can be 12% lower */
if (subs->syncpipe)
minsize -= minsize >> 3;
minsize = max(minsize, 1u);
total_packs = (period_bytes + minsize - 1) / minsize;
/* we need at least two URBs for queueing */
if (total_packs < 2) {
total_packs = 2;
} else {
/* and we don't want too long a queue either */
maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
total_packs = min(total_packs, maxpacks);
}
} else {
while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
urb_packs >>= 1;
total_packs = MAX_URBS * urb_packs;
}
subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
if (subs->nurbs > MAX_URBS) {
/* too much... */
subs->nurbs = MAX_URBS;
total_packs = MAX_URBS * urb_packs;
} else if (subs->nurbs < 2) {
/* too little - we need at least two packets
* to ensure contiguous playback/capture
*/
subs->nurbs = 2;
}
/* allocate and initialize data urbs */
for (i = 0; i < subs->nurbs; i++) {
struct snd_urb_ctx *u = &subs->dataurb[i];
u->index = i;
u->subs = subs;
u->packets = (i + 1) * total_packs / subs->nurbs
- i * total_packs / subs->nurbs;
u->buffer_size = maxsize * u->packets;
if (subs->fmt_type == UAC_FORMAT_TYPE_II)
u->packets++; /* for transfer delimiter */
u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
if (!u->urb)
goto out_of_memory;
u->urb->transfer_buffer =
usb_alloc_coherent(subs->dev, u->buffer_size,
GFP_KERNEL, &u->urb->transfer_dma);
if (!u->urb->transfer_buffer)
goto out_of_memory;
u->urb->pipe = subs->datapipe;
u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
u->urb->interval = 1 << subs->datainterval;
u->urb->context = u;
u->urb->complete = snd_complete_urb;
}
if (subs->syncpipe) {
/* allocate and initialize sync urbs */
subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4,
GFP_KERNEL, &subs->sync_dma);
if (!subs->syncbuf)
goto out_of_memory;
for (i = 0; i < SYNC_URBS; i++) {
struct snd_urb_ctx *u = &subs->syncurb[i];
u->index = i;
u->subs = subs;
u->packets = 1;
u->urb = usb_alloc_urb(1, GFP_KERNEL);
if (!u->urb)
goto out_of_memory;
u->urb->transfer_buffer = subs->syncbuf + i * 4;
u->urb->transfer_dma = subs->sync_dma + i * 4;
u->urb->transfer_buffer_length = 4;
u->urb->pipe = subs->syncpipe;
u->urb->transfer_flags = URB_ISO_ASAP |
URB_NO_TRANSFER_DMA_MAP;
u->urb->number_of_packets = 1;
u->urb->interval = 1 << subs->syncinterval;
u->urb->context = u;
u->urb->complete = snd_complete_sync_urb;
}
}
return 0;
out_of_memory:
snd_usb_release_substream_urbs(subs, 0);
return -ENOMEM;
}
/*
* prepare urb for full speed capture sync pipe
*
* fill the length and offset of each urb descriptor.
* the fixed 10.14 frequency is passed through the pipe.
*/
static int prepare_capture_sync_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
unsigned char *cp = urb->transfer_buffer;
struct snd_urb_ctx *ctx = urb->context;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->iso_frame_desc[0].length = 3;
urb->iso_frame_desc[0].offset = 0;
cp[0] = subs->freqn >> 2;
cp[1] = subs->freqn >> 10;
cp[2] = subs->freqn >> 18;
return 0;
}
/*
* prepare urb for high speed capture sync pipe
*
* fill the length and offset of each urb descriptor.
* the fixed 12.13 frequency is passed as 16.16 through the pipe.
*/
static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
unsigned char *cp = urb->transfer_buffer;
struct snd_urb_ctx *ctx = urb->context;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->iso_frame_desc[0].length = 4;
urb->iso_frame_desc[0].offset = 0;
cp[0] = subs->freqn;
cp[1] = subs->freqn >> 8;
cp[2] = subs->freqn >> 16;
cp[3] = subs->freqn >> 24;
return 0;
}
/*
* process after capture sync complete
* - nothing to do
*/
static int retire_capture_sync_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
return 0;
}
/*
* prepare urb for capture data pipe
*
* fill the offset and length of each descriptor.
*
* we use a temporary buffer to write the captured data.
* since the length of written data is determined by host, we cannot
* write onto the pcm buffer directly... the data is thus copied
* later at complete callback to the global buffer.
*/
static int prepare_capture_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
int i, offs;
struct snd_urb_ctx *ctx = urb->context;
offs = 0;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
for (i = 0; i < ctx->packets; i++) {
urb->iso_frame_desc[i].offset = offs;
urb->iso_frame_desc[i].length = subs->curpacksize;
offs += subs->curpacksize;
}
urb->transfer_buffer_length = offs;
urb->number_of_packets = ctx->packets;
return 0;
}
/*
* process after capture complete
*
* copy the data from each desctiptor to the pcm buffer, and
* update the current position.
*/
static int retire_capture_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
unsigned long flags;
unsigned char *cp;
int i;
unsigned int stride, frames, bytes, oldptr;
int period_elapsed = 0;
stride = runtime->frame_bits >> 3;
for (i = 0; i < urb->number_of_packets; i++) {
cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
if (urb->iso_frame_desc[i].status) {
snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
// continue;
}
bytes = urb->iso_frame_desc[i].actual_length;
frames = bytes / stride;
if (!subs->txfr_quirk)
bytes = frames * stride;
if (bytes % (runtime->sample_bits >> 3) != 0) {
#ifdef CONFIG_SND_DEBUG_VERBOSE
int oldbytes = bytes;
#endif
bytes = frames * stride;
snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
oldbytes, bytes);
}
/* update the current pointer */
spin_lock_irqsave(&subs->lock, flags);
oldptr = subs->hwptr_done;
subs->hwptr_done += bytes;
if (subs->hwptr_done >= runtime->buffer_size * stride)
subs->hwptr_done -= runtime->buffer_size * stride;
frames = (bytes + (oldptr % stride)) / stride;
subs->transfer_done += frames;
if (subs->transfer_done >= runtime->period_size) {
subs->transfer_done -= runtime->period_size;
period_elapsed = 1;
}
spin_unlock_irqrestore(&subs->lock, flags);
/* copy a data chunk */
if (oldptr + bytes > runtime->buffer_size * stride) {
unsigned int bytes1 =
runtime->buffer_size * stride - oldptr;
memcpy(runtime->dma_area + oldptr, cp, bytes1);
memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
} else {
memcpy(runtime->dma_area + oldptr, cp, bytes);
}
}
if (period_elapsed)
snd_pcm_period_elapsed(subs->pcm_substream);
return 0;
}
/*
* Process after capture complete when paused. Nothing to do.
*/
static int retire_paused_capture_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
return 0;
}
/*
* prepare urb for playback sync pipe
*
* set up the offset and length to receive the current frequency.
*/
static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
struct snd_urb_ctx *ctx = urb->context;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize);
urb->iso_frame_desc[0].offset = 0;
return 0;
}
/*
* process after playback sync complete
*
* Full speed devices report feedback values in 10.14 format as samples per
* frame, high speed devices in 16.16 format as samples per microframe.
* Because the Audio Class 1 spec was written before USB 2.0, many high speed
* devices use a wrong interpretation, some others use an entirely different
* format. Therefore, we cannot predict what format any particular device uses
* and must detect it automatically.
*/
static int retire_playback_sync_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
unsigned int f;
int shift;
unsigned long flags;
if (urb->iso_frame_desc[0].status != 0 ||
urb->iso_frame_desc[0].actual_length < 3)
return 0;
f = le32_to_cpup(urb->transfer_buffer);
if (urb->iso_frame_desc[0].actual_length == 3)
f &= 0x00ffffff;
else
f &= 0x0fffffff;
if (f == 0)
return 0;
if (unlikely(subs->freqshift == INT_MIN)) {
/*
* The first time we see a feedback value, determine its format
* by shifting it left or right until it matches the nominal
* frequency value. This assumes that the feedback does not
* differ from the nominal value more than +50% or -25%.
*/
shift = 0;
while (f < subs->freqn - subs->freqn / 4) {
f <<= 1;
shift++;
}
while (f > subs->freqn + subs->freqn / 2) {
f >>= 1;
shift--;
}
subs->freqshift = shift;
}
else if (subs->freqshift >= 0)
f <<= subs->freqshift;
else
f >>= -subs->freqshift;
if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) {
/*
* If the frequency looks valid, set it.
* This value is referred to in prepare_playback_urb().
*/
spin_lock_irqsave(&subs->lock, flags);
subs->freqm = f;
spin_unlock_irqrestore(&subs->lock, flags);
} else {
/*
* Out of range; maybe the shift value is wrong.
* Reset it so that we autodetect again the next time.
*/
subs->freqshift = INT_MIN;
}
return 0;
}
/* determine the number of frames in the next packet */
static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
{
if (subs->fill_max)
return subs->maxframesize;
else {
subs->phase = (subs->phase & 0xffff)
+ (subs->freqm << subs->datainterval);
return min(subs->phase >> 16, subs->maxframesize);
}
}
/*
* Prepare urb for streaming before playback starts or when paused.
*
* We don't have any data, so we send silence.
*/
static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
unsigned int i, offs, counts;
struct snd_urb_ctx *ctx = urb->context;
int stride = runtime->frame_bits >> 3;
offs = 0;
urb->dev = ctx->subs->dev;
for (i = 0; i < ctx->packets; ++i) {
counts = snd_usb_audio_next_packet_size(subs);
urb->iso_frame_desc[i].offset = offs * stride;
urb->iso_frame_desc[i].length = counts * stride;
offs += counts;
}
urb->number_of_packets = ctx->packets;
urb->transfer_buffer_length = offs * stride;
memset(urb->transfer_buffer,
runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
offs * stride);
return 0;
}
/*
* prepare urb for playback data pipe
*
* Since a URB can handle only a single linear buffer, we must use double
* buffering when the data to be transferred overflows the buffer boundary.
* To avoid inconsistencies when updating hwptr_done, we use double buffering
* for all URBs.
*/
static int prepare_playback_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
int i, stride;
unsigned int counts, frames, bytes;
unsigned long flags;
int period_elapsed = 0;
struct snd_urb_ctx *ctx = urb->context;
stride = runtime->frame_bits >> 3;
frames = 0;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
urb->number_of_packets = 0;
spin_lock_irqsave(&subs->lock, flags);
for (i = 0; i < ctx->packets; i++) {
counts = snd_usb_audio_next_packet_size(subs);
/* set up descriptor */
urb->iso_frame_desc[i].offset = frames * stride;
urb->iso_frame_desc[i].length = counts * stride;
frames += counts;
urb->number_of_packets++;
subs->transfer_done += counts;
if (subs->transfer_done >= runtime->period_size) {
subs->transfer_done -= runtime->period_size;
period_elapsed = 1;
if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
if (subs->transfer_done > 0) {
/* FIXME: fill-max mode is not
* supported yet */
frames -= subs->transfer_done;
counts -= subs->transfer_done;
urb->iso_frame_desc[i].length =
counts * stride;
subs->transfer_done = 0;
}
i++;
if (i < ctx->packets) {
/* add a transfer delimiter */
urb->iso_frame_desc[i].offset =
frames * stride;
urb->iso_frame_desc[i].length = 0;
urb->number_of_packets++;
}
break;
}
}
if (period_elapsed) /* finish at the period boundary */
break;
}
bytes = frames * stride;
if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
/* err, the transferred area goes over buffer boundary. */
unsigned int bytes1 =
runtime->buffer_size * stride - subs->hwptr_done;
memcpy(urb->transfer_buffer,
runtime->dma_area + subs->hwptr_done, bytes1);
memcpy(urb->transfer_buffer + bytes1,
runtime->dma_area, bytes - bytes1);
} else {
memcpy(urb->transfer_buffer,
runtime->dma_area + subs->hwptr_done, bytes);
}
subs->hwptr_done += bytes;
if (subs->hwptr_done >= runtime->buffer_size * stride)
subs->hwptr_done -= runtime->buffer_size * stride;
runtime->delay += frames;
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = bytes;
if (period_elapsed)
snd_pcm_period_elapsed(subs->pcm_substream);
return 0;
}
/*
* process after playback data complete
* - decrease the delay count again
*/
static int retire_playback_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime,
struct urb *urb)
{
unsigned long flags;
int stride = runtime->frame_bits >> 3;
int processed = urb->transfer_buffer_length / stride;
spin_lock_irqsave(&subs->lock, flags);
if (processed > runtime->delay)
runtime->delay = 0;
else
runtime->delay -= processed;
spin_unlock_irqrestore(&subs->lock, flags);
return 0;
}
static const char *usb_error_string(int err)
{
switch (err) {
case -ENODEV:
return "no device";
case -ENOENT:
return "endpoint not enabled";
case -EPIPE:
return "endpoint stalled";
case -ENOSPC:
return "not enough bandwidth";
case -ESHUTDOWN:
return "device disabled";
case -EHOSTUNREACH:
return "device suspended";
case -EINVAL:
case -EAGAIN:
case -EFBIG:
case -EMSGSIZE:
return "internal error";
default:
return "unknown error";
}
}
/*
* set up and start data/sync urbs
*/
static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime)
{
unsigned int i;
int err;
if (subs->stream->chip->shutdown)
return -EBADFD;
for (i = 0; i < subs->nurbs; i++) {
if (snd_BUG_ON(!subs->dataurb[i].urb))
return -EINVAL;
if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
goto __error;
}
}
if (subs->syncpipe) {
for (i = 0; i < SYNC_URBS; i++) {
if (snd_BUG_ON(!subs->syncurb[i].urb))
return -EINVAL;
if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
goto __error;
}
}
}
subs->active_mask = 0;
subs->unlink_mask = 0;
subs->running = 1;
for (i = 0; i < subs->nurbs; i++) {
err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
if (err < 0) {
snd_printk(KERN_ERR "cannot submit datapipe "
"for urb %d, error %d: %s\n",
i, err, usb_error_string(err));
goto __error;
}
set_bit(i, &subs->active_mask);
}
if (subs->syncpipe) {
for (i = 0; i < SYNC_URBS; i++) {
err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
if (err < 0) {
snd_printk(KERN_ERR "cannot submit syncpipe "
"for urb %d, error %d: %s\n",
i, err, usb_error_string(err));
goto __error;
}
set_bit(i + 16, &subs->active_mask);
}
}
return 0;
__error:
// snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
deactivate_urbs(subs, 0, 0);
return -EPIPE;
}
/*
*/
static struct snd_urb_ops audio_urb_ops[2] = {
{
.prepare = prepare_nodata_playback_urb,
.retire = retire_playback_urb,
.prepare_sync = prepare_playback_sync_urb,
.retire_sync = retire_playback_sync_urb,
},
{
.prepare = prepare_capture_urb,
.retire = retire_capture_urb,
.prepare_sync = prepare_capture_sync_urb,
.retire_sync = retire_capture_sync_urb,
},
};
/*
* initialize the substream instance.
*/
void snd_usb_init_substream(struct snd_usb_stream *as,
int stream, struct audioformat *fp)
{
struct snd_usb_substream *subs = &as->substream[stream];
INIT_LIST_HEAD(&subs->fmt_list);
spin_lock_init(&subs->lock);
subs->stream = as;
subs->direction = stream;
subs->dev = as->chip->dev;
subs->txfr_quirk = as->chip->txfr_quirk;
subs->ops = audio_urb_ops[stream];
if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH)
subs->ops.prepare_sync = prepare_capture_sync_urb_hs;
snd_usb_set_pcm_ops(as->pcm, stream);
list_add_tail(&fp->list, &subs->fmt_list);
subs->formats |= fp->formats;
subs->endpoint = fp->endpoint;
subs->num_formats++;
subs->fmt_type = fp->fmt_type;
}
int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_usb_substream *subs = substream->runtime->private_data;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
subs->ops.prepare = prepare_playback_urb;
return 0;
case SNDRV_PCM_TRIGGER_STOP:
return deactivate_urbs(subs, 0, 0);
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
subs->ops.prepare = prepare_nodata_playback_urb;
return 0;
}
return -EINVAL;
}
int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_usb_substream *subs = substream->runtime->private_data;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
subs->ops.retire = retire_capture_urb;
return start_urbs(subs, substream->runtime);
case SNDRV_PCM_TRIGGER_STOP:
return deactivate_urbs(subs, 0, 0);
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
subs->ops.retire = retire_paused_capture_urb;
return 0;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
subs->ops.retire = retire_capture_urb;
return 0;
}
return -EINVAL;
}
int snd_usb_substream_prepare(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime)
{
/* clear urbs (to be sure) */
deactivate_urbs(subs, 0, 1);
wait_clear_urbs(subs);
/* for playback, submit the URBs now; otherwise, the first hwptr_done
* updates for all URBs would happen at the same time when starting */
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
subs->ops.prepare = prepare_nodata_playback_urb;
return start_urbs(subs, runtime);
}
return 0;
}

View File

@ -1,21 +0,0 @@
#ifndef __USBAUDIO_URB_H
#define __USBAUDIO_URB_H
void snd_usb_init_substream(struct snd_usb_stream *as,
int stream,
struct audioformat *fp);
int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
unsigned int period_bytes,
unsigned int rate,
unsigned int frame_bits);
void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
int snd_usb_substream_prepare(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime);
int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
#endif /* __USBAUDIO_URB_H */

View File

@ -80,6 +80,7 @@ enum quirk_type {
QUIRK_MIDI_CME, QUIRK_MIDI_CME,
QUIRK_MIDI_AKAI, QUIRK_MIDI_AKAI,
QUIRK_MIDI_US122L, QUIRK_MIDI_US122L,
QUIRK_MIDI_FTDI,
QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_STANDARD_INTERFACE,
QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_FIXED_ENDPOINT,
QUIRK_AUDIO_EDIROL_UAXX, QUIRK_AUDIO_EDIROL_UAXX,