@ -18,6 +18,7 @@
# include <linux/slab.h>
# include <linux/usb.h>
# include <linux/usb/audio.h>
# include <linux/usb/midi.h>
# include <sound/control.h>
# include <sound/core.h>
@ -175,6 +176,178 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
return 0 ;
}
static int create_auto_pcm_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver )
{
struct usb_host_interface * alts ;
struct usb_interface_descriptor * altsd ;
struct usb_endpoint_descriptor * epd ;
struct uac1_as_header_descriptor * ashd ;
struct uac_format_type_i_discrete_descriptor * fmtd ;
/*
* Most Roland / Yamaha audio streaming interfaces have more or less
* standard descriptors , but older devices might lack descriptors , and
* future ones might change , so ensure that we fail silently if the
* interface doesn ' t look exactly right .
*/
/* must have a non-zero altsetting for streaming */
if ( iface - > num_altsetting < 2 )
return - ENODEV ;
alts = & iface - > altsetting [ 1 ] ;
altsd = get_iface_desc ( alts ) ;
/* must have an isochronous endpoint for streaming */
if ( altsd - > bNumEndpoints < 1 )
return - ENODEV ;
epd = get_endpoint ( alts , 0 ) ;
if ( ! usb_endpoint_xfer_isoc ( epd ) )
return - ENODEV ;
/* must have format descriptors */
ashd = snd_usb_find_csint_desc ( alts - > extra , alts - > extralen , NULL ,
UAC_AS_GENERAL ) ;
fmtd = snd_usb_find_csint_desc ( alts - > extra , alts - > extralen , NULL ,
UAC_FORMAT_TYPE ) ;
if ( ! ashd | | ashd - > bLength < 7 | |
! fmtd | | fmtd - > bLength < 8 )
return - ENODEV ;
return create_standard_audio_quirk ( chip , iface , driver , NULL ) ;
}
static int create_yamaha_midi_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
struct usb_host_interface * alts )
{
static const struct snd_usb_audio_quirk yamaha_midi_quirk = {
. type = QUIRK_MIDI_YAMAHA
} ;
struct usb_midi_in_jack_descriptor * injd ;
struct usb_midi_out_jack_descriptor * outjd ;
/* must have some valid jack descriptors */
injd = snd_usb_find_csint_desc ( alts - > extra , alts - > extralen ,
NULL , USB_MS_MIDI_IN_JACK ) ;
outjd = snd_usb_find_csint_desc ( alts - > extra , alts - > extralen ,
NULL , USB_MS_MIDI_OUT_JACK ) ;
if ( ! injd & & ! outjd )
return - ENODEV ;
if ( injd & & ( injd - > bLength < 5 | |
( injd - > bJackType ! = USB_MS_EMBEDDED & &
injd - > bJackType ! = USB_MS_EXTERNAL ) ) )
return - ENODEV ;
if ( outjd & & ( outjd - > bLength < 6 | |
( outjd - > bJackType ! = USB_MS_EMBEDDED & &
outjd - > bJackType ! = USB_MS_EXTERNAL ) ) )
return - ENODEV ;
return create_any_midi_quirk ( chip , iface , driver , & yamaha_midi_quirk ) ;
}
static int create_roland_midi_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
struct usb_host_interface * alts )
{
static const struct snd_usb_audio_quirk roland_midi_quirk = {
. type = QUIRK_MIDI_ROLAND
} ;
u8 * roland_desc = NULL ;
/* might have a vendor-specific descriptor <06 24 F1 02 ...> */
for ( ; ; ) {
roland_desc = snd_usb_find_csint_desc ( alts - > extra ,
alts - > extralen ,
roland_desc , 0xf1 ) ;
if ( ! roland_desc )
return - ENODEV ;
if ( roland_desc [ 0 ] < 6 | | roland_desc [ 3 ] ! = 2 )
continue ;
return create_any_midi_quirk ( chip , iface , driver ,
& roland_midi_quirk ) ;
}
}
static int create_std_midi_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
struct usb_host_interface * alts )
{
struct usb_ms_header_descriptor * mshd ;
struct usb_ms_endpoint_descriptor * msepd ;
/* must have the MIDIStreaming interface header descriptor*/
mshd = ( struct usb_ms_header_descriptor * ) alts - > extra ;
if ( alts - > extralen < 7 | |
mshd - > bLength < 7 | |
mshd - > bDescriptorType ! = USB_DT_CS_INTERFACE | |
mshd - > bDescriptorSubtype ! = USB_MS_HEADER )
return - ENODEV ;
/* must have the MIDIStreaming endpoint descriptor*/
msepd = ( struct usb_ms_endpoint_descriptor * ) alts - > endpoint [ 0 ] . extra ;
if ( alts - > endpoint [ 0 ] . extralen < 4 | |
msepd - > bLength < 4 | |
msepd - > bDescriptorType ! = USB_DT_CS_ENDPOINT | |
msepd - > bDescriptorSubtype ! = UAC_MS_GENERAL | |
msepd - > bNumEmbMIDIJack < 1 | |
msepd - > bNumEmbMIDIJack > 16 )
return - ENODEV ;
return create_any_midi_quirk ( chip , iface , driver , NULL ) ;
}
static int create_auto_midi_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver )
{
struct usb_host_interface * alts ;
struct usb_interface_descriptor * altsd ;
struct usb_endpoint_descriptor * epd ;
int err ;
alts = & iface - > altsetting [ 0 ] ;
altsd = get_iface_desc ( alts ) ;
/* must have at least one bulk/interrupt endpoint for streaming */
if ( altsd - > bNumEndpoints < 1 )
return - ENODEV ;
epd = get_endpoint ( alts , 0 ) ;
if ( ! usb_endpoint_xfer_bulk ( epd ) | |
! usb_endpoint_xfer_int ( epd ) )
return - ENODEV ;
switch ( USB_ID_VENDOR ( chip - > usb_id ) ) {
case 0x0499 : /* Yamaha */
err = create_yamaha_midi_quirk ( chip , iface , driver , alts ) ;
if ( err < 0 & & err ! = - ENODEV )
return err ;
break ;
case 0x0582 : /* Roland */
err = create_roland_midi_quirk ( chip , iface , driver , alts ) ;
if ( err < 0 & & err ! = - ENODEV )
return err ;
break ;
}
return create_std_midi_quirk ( chip , iface , driver , alts ) ;
}
static int create_autodetect_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
int err ;
err = create_auto_pcm_quirk ( chip , iface , driver ) ;
if ( err = = - ENODEV )
err = create_auto_midi_quirk ( chip , iface , driver ) ;
return err ;
}
/*
* Create a stream for an Edirol UA - 700 / UA - 25 / UA - 4F X interface .
* The only way to detect the sample rate is by looking at wMaxPacketSize .
@ -303,9 +476,11 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
static const quirk_func_t quirk_funcs [ ] = {
[ QUIRK_IGNORE_INTERFACE ] = ignore_interface_quirk ,
[ QUIRK_COMPOSITE ] = create_composite_quirk ,
[ QUIRK_AUTODETECT ] = create_autodetect_quirk ,
[ QUIRK_MIDI_STANDARD_INTERFACE ] = create_any_midi_quirk ,
[ QUIRK_MIDI_FIXED_ENDPOINT ] = create_any_midi_quirk ,
[ QUIRK_MIDI_YAMAHA ] = create_any_midi_quirk ,
[ QUIRK_MIDI_ROLAND ] = create_any_midi_quirk ,
[ QUIRK_MIDI_MIDIMAN ] = create_any_midi_quirk ,
[ QUIRK_MIDI_NOVATION ] = create_any_midi_quirk ,
[ QUIRK_MIDI_RAW_BYTES ] = create_any_midi_quirk ,