Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
9fd6aa65
Commit
9fd6aa65
authored
Oct 06, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux-sound.bkbits.net/linux-sound
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
ab1180be
273639ad
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
745 additions
and
325 deletions
+745
-325
include/sound/version.h
include/sound/version.h
+1
-1
sound/core/info.c
sound/core/info.c
+0
-6
sound/core/sound.c
sound/core/sound.c
+0
-9
sound/pci/Config.in
sound/pci/Config.in
+2
-2
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos.c
+0
-1
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/cs46xx/dsp_spos_scb_lib.c
+0
-1
sound/sound_core.c
sound/sound_core.c
+10
-5
sound/usb/usbaudio.c
sound/usb/usbaudio.c
+100
-57
sound/usb/usbaudio.h
sound/usb/usbaudio.h
+22
-7
sound/usb/usbmidi.c
sound/usb/usbmidi.c
+307
-88
sound/usb/usbquirks.h
sound/usb/usbquirks.h
+303
-148
No files found.
include/sound/version.h
View file @
9fd6aa65
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc3"
#define CONFIG_SND_DATE " (
Tue Oct 01 14:40:2
3 2002 UTC)"
#define CONFIG_SND_DATE " (
Fri Oct 04 13:09:1
3 2002 UTC)"
sound/core/info.c
View file @
9fd6aa65
...
...
@@ -960,7 +960,6 @@ void snd_info_free_device(snd_info_entry_t * entry)
{
#ifdef CONFIG_DEVFS_FS
char
dname
[
32
];
devfs_handle_t
master
;
#endif
snd_runtime_check
(
entry
,
return
);
...
...
@@ -970,12 +969,7 @@ void snd_info_free_device(snd_info_entry_t * entry)
#ifdef CONFIG_DEVFS_FS
if
(
entry
->
p
&&
strncmp
(
entry
->
name
,
"controlC"
,
8
))
{
sprintf
(
dname
,
"snd/%s"
,
entry
->
name
);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
master
=
devfs_find_handle
(
NULL
,
dname
,
strlen
(
dname
),
0
,
0
,
DEVFS_SPECIAL_CHR
,
0
);
devfs_unregister
(
master
);
#else
devfs_find_and_unregister
(
NULL
,
dname
,
0
,
0
,
DEVFS_SPECIAL_CHR
,
0
);
#endif
}
#endif
snd_info_free_entry
(
entry
);
...
...
sound/core/sound.c
View file @
9fd6aa65
...
...
@@ -358,21 +358,12 @@ static int __init alsa_sound_init(void)
static
void
__exit
alsa_sound_exit
(
void
)
{
#ifdef CONFIG_DEVFS_FS
devfs_handle_t
master
;
char
controlname
[
24
];
short
controlnum
;
for
(
controlnum
=
0
;
controlnum
<
snd_cards_limit
;
controlnum
++
)
{
sprintf
(
controlname
,
"snd/controlC%d"
,
controlnum
);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
master
=
devfs_find_handle
(
NULL
,
controlname
,
strlen
(
controlname
),
0
,
0
,
DEVFS_SPECIAL_CHR
,
0
);
devfs_unregister
(
master
);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
master
=
devfs_find_handle
(
NULL
,
controlname
,
0
,
0
,
DEVFS_SPECIAL_CHR
,
0
);
devfs_unregister
(
master
);
#else
devfs_find_and_unregister
(
NULL
,
controlname
,
0
,
0
,
DEVFS_SPECIAL_CHR
,
0
);
#endif
}
#endif
...
...
sound/pci/Config.in
View file @
9fd6aa65
...
...
@@ -7,7 +7,7 @@ dep_tristate 'ALi PCI Audio M5451' CONFIG_SND_ALI5451 $CONFIG_SND
dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SND_CS46XX $CONFIG_SND
dep_mbool ' Cirrus Logic (Sound Fusion) New DSP support (EXPERIMENTAL)' CONFIG_SND_CS46XX_NEW_DSP $CONFIG_SND_CS46XX $CONFIG_EXPERIMENTAL
dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND
dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
dep_tristate 'EMU10K1 (SB Live!
& Audigy
, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND
dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND
dep_tristate 'RME Digi32, 32/8, 32 PRO' CONFIG_SND_RME32 $CONFIG_SND
...
...
@@ -25,7 +25,7 @@ dep_tristate 'ESS ES1968/1978 (Maestro-1/2/2E)' CONFIG_SND_ES1968 $CONFIG_SND
dep_tristate 'ESS Allegro/Maestro3' CONFIG_SND_MAESTRO3 $CONFIG_SND
dep_tristate 'ForteMedia FM801' CONFIG_SND_FM801 $CONFIG_SND
dep_tristate 'ICEnsemble ICE1712 (Envy24)' CONFIG_SND_ICE1712 $CONFIG_SND
dep_tristate 'Intel i8
10/i820/i830/i840/MX440 integrated audio
' CONFIG_SND_INTEL8X0 $CONFIG_SND
dep_tristate 'Intel i8
x0/MX440, SiS 7012; Ali 5455; NForce Audio; AMD768/8111
' CONFIG_SND_INTEL8X0 $CONFIG_SND
dep_tristate 'S3 SonicVibes' CONFIG_SND_SONICVIBES $CONFIG_SND
dep_tristate 'VIA 82C686A/B, 8233 South Bridge' CONFIG_SND_VIA82XX $CONFIG_SND
...
...
sound/pci/cs46xx/dsp_spos.c
View file @
9fd6aa65
...
...
@@ -1577,7 +1577,6 @@ int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
int
cs46xx_dsp_enable_spdif_in
(
cs46xx_t
*
chip
)
{
dsp_spos_instance_t
*
ins
=
chip
->
dsp_spos_instance
;
unsigned
int
flags
;
/* turn on amplifier */
chip
->
active_ctrl
(
chip
,
1
);
...
...
sound/pci/cs46xx/dsp_spos_scb_lib.c
View file @
9fd6aa65
...
...
@@ -1410,7 +1410,6 @@ int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src)
{
dsp_spos_instance_t
*
ins
=
chip
->
dsp_spos_instance
;
dsp_scb_descriptor_t
*
parent_scb
;
unsigned
int
flags
;
snd_assert
(
src
->
parent_scb_ptr
==
NULL
,
return
-
EINVAL
);
snd_assert
(
ins
->
master_mix_scb
!=
NULL
,
return
-
EINVAL
);
...
...
sound/sound_core.c
View file @
9fd6aa65
...
...
@@ -122,7 +122,7 @@ static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list,
* Remove a node from the chain. Called with the lock asserted
*/
static
void
__sound_remove_unit
(
struct
sound_unit
**
list
,
int
unit
)
static
struct
sound_unit
*
__sound_remove_unit
(
struct
sound_unit
**
list
,
int
unit
)
{
while
(
*
list
)
{
...
...
@@ -130,13 +130,12 @@ static void __sound_remove_unit(struct sound_unit **list, int unit)
if
(
p
->
unit_minor
==
unit
)
{
*
list
=
p
->
next
;
devfs_unregister
(
p
->
de
);
kfree
(
p
);
return
;
return
p
;
}
list
=&
(
p
->
next
);
}
printk
(
KERN_ERR
"Sound device %d went missing!
\n
"
,
unit
);
return
NULL
;
}
/*
...
...
@@ -189,9 +188,15 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
static
void
sound_remove_unit
(
struct
sound_unit
**
list
,
int
unit
)
{
struct
sound_unit
*
p
;
spin_lock
(
&
sound_loader_lock
);
__sound_remove_unit
(
list
,
unit
);
p
=
__sound_remove_unit
(
list
,
unit
);
spin_unlock
(
&
sound_loader_lock
);
if
(
p
)
{
devfs_unregister
(
p
->
de
);
kfree
(
p
);
}
}
/*
...
...
sound/usb/usbaudio.c
View file @
9fd6aa65
...
...
@@ -284,6 +284,16 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
urb
->
transfer_buffer
=
ctx
->
buf
;
urb
->
transfer_buffer_length
=
offs
;
urb
->
interval
=
1
;
#if 0 // for check
if (! urb->bandwidth) {
int bustime;
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0)
return bustime;
printk("urb %d: bandwidth = %d (packets = %d)\n", ctx->index, bustime, urb->number_of_packets);
usb_claim_bandwidth(urb->dev, urb, bustime, 1);
}
#endif // for check
return
0
;
}
...
...
@@ -305,8 +315,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
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
)
/* active? hmm, skip this */
continue
;
if
(
urb
->
iso_frame_desc
[
i
].
status
)
{
snd_printd
(
KERN_ERR
"frame %d active: %d
\n
"
,
i
,
urb
->
iso_frame_desc
[
i
].
status
);
// continue;
}
len
=
urb
->
iso_frame_desc
[
i
].
actual_length
/
stride
;
if
(
!
len
)
continue
;
...
...
@@ -1009,6 +1021,7 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
}
/* if endpoint has sampling rate control, set it */
if
(
fmt
->
attributes
&
EP_CS_ATTR_SAMPLE_RATE
)
{
int
crate
;
data
[
0
]
=
runtime
->
rate
;
data
[
1
]
=
runtime
->
rate
>>
8
;
data
[
2
]
=
runtime
->
rate
>>
16
;
...
...
@@ -1026,8 +1039,11 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
dev
->
devnum
,
subs
->
interface
,
fmt
->
altsetting
,
ep
);
return
err
;
}
runtime
->
rate
=
data
[
0
]
|
(
data
[
1
]
<<
8
)
|
(
data
[
2
]
<<
16
);
// printk("ok, getting back rate to %d\n", runtime->rate);
crate
=
data
[
0
]
|
(
data
[
1
]
<<
8
)
|
(
data
[
2
]
<<
16
);
if
(
crate
!=
runtime
->
rate
)
{
snd_printd
(
KERN_WARNING
"current rate %d is different from the runtime rate %d
\n
"
,
crate
,
runtime
->
rate
);
// runtime->rate = crate;
}
}
/* always fill max packet size */
if
(
fmt
->
attributes
&
EP_CS_ATTR_FILL_MAX
)
...
...
@@ -1292,14 +1308,14 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype
* entry point for linux usb interface
*/
#if
n
def OLD_USB
static
int
usb_audio_probe
(
struct
usb_interface
*
intf
,
#ifdef OLD_USB
static
void
*
usb_audio_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
);
static
void
usb_audio_disconnect
(
struct
usb_
interface
*
intf
);
static
void
usb_audio_disconnect
(
struct
usb_
device
*
dev
,
void
*
ptr
);
#else
static
void
*
usb_audio_probe
(
usb_device
*
dev
,
unsigned
int
ifnum
,
static
int
usb_audio_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
);
static
void
usb_audio_disconnect
(
struct
usb_
device
*
dev
,
void
*
ptr
);
static
void
usb_audio_disconnect
(
struct
usb_
interface
*
intf
);
#endif
static
struct
usb_device_id
usb_audio_ids
[]
=
{
...
...
@@ -1810,7 +1826,8 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, unsigned char *buffer, i
* parse audio control descriptor and create pcm/midi streams
*/
static
int
snd_usb_create_midi_interface
(
snd_usb_audio_t
*
chip
,
int
ifnum
,
static
int
snd_usb_create_midi_interface
(
snd_usb_audio_t
*
chip
,
struct
usb_interface
*
iface
,
const
snd_usb_audio_quirk_t
*
quirk
);
static
int
snd_usb_create_streams
(
snd_usb_audio_t
*
chip
,
int
ctrlif
,
...
...
@@ -1850,7 +1867,7 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
}
if
(
iface
->
altsetting
[
0
].
bInterfaceClass
==
USB_CLASS_AUDIO
&&
iface
->
altsetting
[
0
].
bInterfaceSubClass
==
USB_SUBCLASS_MIDI_STREAMING
)
{
if
(
snd_usb_create_midi_interface
(
chip
,
j
,
NULL
)
<
0
)
{
if
(
snd_usb_create_midi_interface
(
chip
,
iface
,
NULL
)
<
0
)
{
snd_printk
(
KERN_ERR
"%d:%u:%d: cannot create sequencer device
\n
"
,
dev
->
devnum
,
ctrlif
,
j
);
continue
;
}
...
...
@@ -1871,7 +1888,8 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
return
0
;
}
static
int
snd_usb_create_midi_interface
(
snd_usb_audio_t
*
chip
,
int
ifnum
,
static
int
snd_usb_create_midi_interface
(
snd_usb_audio_t
*
chip
,
struct
usb_interface
*
iface
,
const
snd_usb_audio_quirk_t
*
quirk
)
{
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
...
...
@@ -1888,18 +1906,20 @@ static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum,
strcpy
(
seq_device
->
name
,
chip
->
card
->
shortname
);
umidi
=
(
snd_usb_midi_t
*
)
SNDRV_SEQ_DEVICE_ARGPTR
(
seq_device
);
umidi
->
chip
=
chip
;
umidi
->
ifnum
=
ifnum
;
umidi
->
iface
=
iface
;
umidi
->
ifnum
=
iface
->
altsetting
->
bInterfaceNumber
;
umidi
->
quirk
=
quirk
;
umidi
->
seq_client
=
-
1
;
#endif
return
0
;
}
static
inline
int
snd_usb_create_quirk
(
snd_usb_audio_t
*
chip
,
int
ifnum
,
static
inline
int
snd_usb_create_quirk
(
snd_usb_audio_t
*
chip
,
struct
usb_interface
*
iface
,
const
snd_usb_audio_quirk_t
*
quirk
)
{
/* in the future, there may be quirks for PCM devices */
return
snd_usb_create_midi_interface
(
chip
,
if
num
,
quirk
);
return
snd_usb_create_midi_interface
(
chip
,
if
ace
,
quirk
);
}
...
...
@@ -2050,27 +2070,18 @@ static int alloc_desc_buffer(struct usb_device *dev, int index, unsigned char **
* only at the first time. the successive calls of this function will
* append the pcm interface to the corresponding card.
*/
#ifndef OLD_USB
static
int
usb_audio_probe
(
struct
usb_interface
*
intf
,
static
void
*
snd_usb_audio_probe
(
struct
usb_device
*
dev
,
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
#else
static
void
*
usb_audio_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
)
#endif
{
#ifndef OLD_USB
struct
usb_device
*
dev
=
interface_to_usbdev
(
intf
);
int
ifnum
=
intf
->
altsetting
->
bInterfaceNumber
;
#endif
struct
usb_config_descriptor
*
config
=
dev
->
actconfig
;
const
snd_usb_audio_quirk_t
*
quirk
=
(
const
snd_usb_audio_quirk_t
*
)
id
->
driver_info
;
unsigned
char
*
buffer
;
unsigned
int
index
;
int
i
,
buflen
;
int
i
;
snd_card_t
*
card
;
snd_usb_audio_t
*
chip
;
int
ifnum
=
intf
->
altsetting
->
bInterfaceNumber
;
if
(
quirk
&&
ifnum
!=
quirk
->
ifnum
)
if
(
quirk
&&
quirk
->
ifnum
!=
QUIRK_ANY_INTERFACE
&&
ifnum
!=
quirk
->
ifnum
)
goto
__err_val
;
if
(
usb_set_configuration
(
dev
,
config
->
bConfigurationValue
)
<
0
)
{
...
...
@@ -2078,11 +2089,6 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
goto
__err_val
;
}
index
=
dev
->
actconfig
-
config
;
buflen
=
alloc_desc_buffer
(
dev
,
index
,
&
buffer
);
if
(
buflen
<=
0
)
goto
__err_val
;
/*
* found a config. now register to ALSA
*/
...
...
@@ -2124,12 +2130,24 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
}
if
(
!
quirk
)
{
if
(
snd_usb_create_streams
(
chip
,
ifnum
,
buffer
,
buflen
)
<
0
)
/* USB audio interface */
unsigned
char
*
buffer
;
unsigned
int
index
;
int
buflen
;
index
=
dev
->
actconfig
-
config
;
buflen
=
alloc_desc_buffer
(
dev
,
index
,
&
buffer
);
if
(
buflen
<=
0
)
goto
__error
;
if
(
snd_usb_create_mixer
(
chip
,
ifnum
,
buffer
,
buflen
)
<
0
)
if
(
snd_usb_create_streams
(
chip
,
ifnum
,
buffer
,
buflen
)
<
0
||
snd_usb_create_mixer
(
chip
,
ifnum
,
buffer
,
buflen
)
<
0
)
{
kfree
(
buffer
);
goto
__error
;
}
kfree
(
buffer
);
}
else
{
if
(
snd_usb_create_quirk
(
chip
,
ifnum
,
quirk
)
<
0
)
/* USB midi interface */
if
(
snd_usb_create_quirk
(
chip
,
intf
,
quirk
)
<
0
)
goto
__error
;
}
...
...
@@ -2142,38 +2160,20 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
chip
->
num_interfaces
++
;
up
(
&
register_mutex
);
kfree
(
buffer
);
#ifndef OLD_USB
return
0
;
#else
return
chip
;
#endif
__error:
up
(
&
register_mutex
);
kfree
(
buffer
);
__err_val:
#ifndef OLD_USB
return
-
EIO
;
#else
return
NULL
;
#endif
}
/*
* we need to take care of counter, since disconnection can be called also
* many times as well as usb_audio_probe().
*/
#ifndef OLD_USB
static
void
usb_audio_disconnect
(
struct
usb_interface
*
intf
)
#else
static
void
usb_audio_disconnect
(
struct
usb_device
*
dev
,
void
*
ptr
)
#endif
static
void
snd_usb_audio_disconnect
(
struct
usb_device
*
dev
,
void
*
ptr
)
{
#ifndef OLD_USB
void
*
ptr
=
dev_get_drvdata
(
&
intf
->
dev
);
#endif
snd_usb_audio_t
*
chip
;
if
(
ptr
==
(
void
*
)
-
1
)
...
...
@@ -2185,6 +2185,49 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
snd_card_free
(
chip
->
card
);
}
#ifdef OLD_USB
/*
* 2.4 USB kernel API
*/
static
void
*
usb_audio_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
)
{
return
snd_usb_audio_probe
(
dev
,
usb_ifnum_to_if
(
dev
,
ifnum
),
id
);
}
static
void
usb_audio_disconnect
(
struct
usb_device
*
dev
,
void
*
ptr
)
{
snd_usb_audio_disconnect
(
dev
,
ptr
);
}
#else
/*
* new 2.5 USB kernel API
*/
static
int
usb_audio_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
void
*
chip
;
chip
=
snd_usb_audio_probe
(
interface_to_usbdev
(
intf
),
intf
,
id
);
if
(
chip
)
{
dev_set_drvdata
(
&
intf
->
dev
,
chip
);
return
0
;
}
else
return
-
EIO
;
}
static
void
usb_audio_disconnect
(
struct
usb_interface
*
intf
)
{
snd_usb_audio_disconnect
(
interface_to_usbdev
(
intf
),
dev_get_drvdata
(
&
intf
->
dev
));
}
#endif
static
int
__init
snd_usb_audio_init
(
void
)
{
usb_register
(
&
usb_audio_driver
);
...
...
sound/usb/usbaudio.h
View file @
9fd6aa65
...
...
@@ -58,6 +58,8 @@
#define EP_GENERAL 0x01
#define MS_GENERAL 0x01
#define MIDI_IN_JACK 0x02
#define MIDI_OUT_JACK 0x03
/* endpoint attributes */
#define EP_ATTR_MASK 0x0c
...
...
@@ -146,22 +148,34 @@ struct snd_usb_audio {
/*
* Information about devices with broken descriptors
*/
#define QUIRK_ANY_INTERFACE -1
#define QUIRK_MIDI_FIXED_ENDPOINT 0
#define QUIRK_MIDI_YAMAHA 1
#define QUIRK_MIDI_MIDIMAN 2
typedef
struct
snd_usb_audio_quirk
snd_usb_audio_quirk_t
;
typedef
struct
snd_usb_midi_endpoint_info
snd_usb_midi_endpoint_info_t
;
struct
snd_usb_audio_quirk
{
const
char
*
vendor_name
;
const
char
*
product_name
;
int
ifnum
;
int16_t
ifnum
;
int16_t
type
;
const
void
*
data
;
};
/* MIDI specific
*/
struct
snd_usb_midi_endpoint_info
{
/* data for QUIRK_MIDI_FIXED_ENDPOINT
*/
struct
snd_usb_midi_endpoint_info
{
int16_t
epnum
;
/* ep number, -1 autodetect */
uint16_t
out_cables
;
/* bitmask */
uint16_t
in_cables
;
/* bitmask */
}
endpoints
[
MIDI_MAX_ENDPOINTS
];
};
/* for QUIRK_MIDI_YAMAHA, data is NULL */
/* for QUIRK_MIDI_MIDIMAN, data is the number of ports */
/*
* USB MIDI sequencer device data
*/
...
...
@@ -173,6 +187,7 @@ typedef struct snd_usb_midi_in_endpoint snd_usb_midi_in_endpoint_t;
struct
snd_usb_midi
{
/* filled by usbaudio.c */
snd_usb_audio_t
*
chip
;
struct
usb_interface
*
iface
;
int
ifnum
;
const
snd_usb_audio_quirk_t
*
quirk
;
...
...
sound/usb/usbmidi.c
View file @
9fd6aa65
...
...
@@ -4,6 +4,10 @@
* Copyright (c) 2002 Clemens Ladisch
* All rights reserved.
*
* Based on the OSS usb-midi driver by NAGANO Daisuke,
* NetBSD's umidi driver by Takuya SHIOZAKI,
* the "USB Device Class Definition for MIDI Devices" by Roland
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
...
...
@@ -120,6 +124,10 @@ struct snd_usb_midi_in_endpoint {
static
void
snd_usbmidi_do_output
(
snd_usb_midi_out_endpoint_t
*
ep
);
static
const
uint8_t
snd_usbmidi_cin_length
[]
=
{
0
,
0
,
2
,
3
,
3
,
1
,
2
,
3
,
3
,
3
,
3
,
3
,
2
,
2
,
3
,
1
};
/*
* Submits the URB, with error handling.
*/
...
...
@@ -152,9 +160,6 @@ static int snd_usbmidi_urb_error(int status)
static
void
snd_usbmidi_input_packet
(
snd_usb_midi_in_endpoint_t
*
ep
,
uint8_t
packet
[
4
])
{
static
const
uint8_t
cin_length
[]
=
{
0
,
0
,
2
,
3
,
3
,
1
,
2
,
3
,
3
,
3
,
3
,
3
,
2
,
2
,
3
,
1
};
int
cable
=
packet
[
0
]
>>
4
;
usbmidi_in_port_t
*
port
=
&
ep
->
ports
[
cable
];
snd_seq_event_t
ev
;
...
...
@@ -163,7 +168,7 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
return
;
memset
(
&
ev
,
0
,
sizeof
(
ev
));
if
(
snd_midi_event_encode
(
port
->
midi_event
,
&
packet
[
1
],
cin_length
[
packet
[
0
]
&
0x0f
],
&
ev
)
>
0
snd_usbmidi_
cin_length
[
packet
[
0
]
&
0x0f
],
&
ev
)
>
0
&&
ev
.
type
!=
SNDRV_SEQ_EVENT_NONE
)
{
ev
.
source
.
port
=
port
->
seq_port
;
ev
.
dest
.
client
=
SNDRV_SEQ_ADDRESS_SUBSCRIBERS
;
...
...
@@ -199,6 +204,38 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
}
}
/*
* Converts the data read from a Midiman device to standard USB MIDI packets.
*/
static
void
snd_usbmidi_in_midiman_complete
(
struct
urb
*
urb
)
{
if
(
urb
->
status
==
0
)
{
uint8_t
*
buffer
=
(
uint8_t
*
)
urb
->
transfer_buffer
;
int
i
;
for
(
i
=
0
;
i
+
4
<=
urb
->
actual_length
;
i
+=
4
)
{
if
(
buffer
[
i
+
3
]
!=
0
)
{
/*
* snd_usbmidi_input_packet() doesn't check the
* contents of the message, so we simply use
* some random CIN with the desired length.
*/
static
const
uint8_t
cin
[
4
]
=
{
0x0
,
0xf
,
0x2
,
0x3
};
uint8_t
ctl
=
buffer
[
i
+
3
];
buffer
[
i
+
3
]
=
buffer
[
i
+
2
];
buffer
[
i
+
2
]
=
buffer
[
i
+
1
];
buffer
[
i
+
1
]
=
buffer
[
i
+
0
];
buffer
[
i
+
0
]
=
(
ctl
&
0xf0
)
|
cin
[
ctl
&
3
];
}
else
{
buffer
[
i
+
0
]
=
0
;
}
}
}
snd_usbmidi_in_urb_complete
(
urb
);
}
static
void
snd_usbmidi_out_urb_complete
(
struct
urb
*
urb
)
{
snd_usb_midi_out_endpoint_t
*
ep
=
snd_magic_cast
(
snd_usb_midi_out_endpoint_t
,
urb
->
context
,
return
);
...
...
@@ -213,6 +250,23 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)
spin_unlock_irqrestore
(
&
ep
->
buffer_lock
,
flags
);
}
/*
* Converts standard USB MIDI packets to what Midman devices expect.
*/
static
void
snd_usbmidi_convert_to_midiman
(
struct
urb
*
urb
)
{
uint8_t
*
buffer
=
(
uint8_t
*
)
urb
->
transfer_buffer
;
int
i
;
for
(
i
=
0
;
i
+
4
<=
urb
->
transfer_buffer_length
;
i
+=
4
)
{
uint8_t
cin
=
buffer
[
i
];
buffer
[
i
+
0
]
=
buffer
[
i
+
1
];
buffer
[
i
+
1
]
=
buffer
[
i
+
2
];
buffer
[
i
+
2
]
=
buffer
[
i
+
3
];
buffer
[
i
+
3
]
=
(
cin
&
0xf0
)
|
snd_usbmidi_cin_length
[
cin
&
0x0f
];
}
}
/*
* This is called when some data should be transferred to the device
* (after the reception of one or more sequencer events, or after completion
...
...
@@ -255,6 +309,9 @@ static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep)
}
if
(
len
>
0
)
{
if
(
ep
->
umidi
->
quirk
&&
ep
->
umidi
->
quirk
->
type
==
QUIRK_MIDI_MIDIMAN
)
snd_usbmidi_convert_to_midiman
(
ep
->
urb
);
ep
->
urb
->
dev
=
ep
->
umidi
->
chip
->
dev
;
snd_usbmidi_submit_urb
(
ep
->
urb
,
GFP_ATOMIC
);
}
...
...
@@ -479,22 +536,6 @@ static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
snd_magic_kfree
(
ep
);
}
#ifndef OLD_USB
/* this code is not exported from USB core anymore */
struct
usb_interface
*
local_usb_ifnum_to_if
(
struct
usb_device
*
dev
,
unsigned
ifnum
)
{
int
i
;
for
(
i
=
0
;
i
<
dev
->
actconfig
->
bNumInterfaces
;
i
++
)
if
(
dev
->
actconfig
->
interface
[
i
].
altsetting
[
0
].
bInterfaceNumber
==
ifnum
)
return
&
dev
->
actconfig
->
interface
[
i
];
return
NULL
;
}
#else
#define local_usb_ifnum_to_if usb_ifnum_to_if
#endif
/*
* For Roland devices, use the alternate setting which uses interrupt
* transfers for input.
...
...
@@ -507,7 +548,7 @@ static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi,
if
(
umidi
->
chip
->
dev
->
descriptor
.
idVendor
!=
0x0582
)
return
NULL
;
intf
=
local_usb_ifnum_to_if
(
umidi
->
chip
->
dev
,
umidi
->
ifnum
)
;
intf
=
umidi
->
iface
;
if
(
!
intf
||
intf
->
num_altsetting
!=
2
)
return
NULL
;
...
...
@@ -528,6 +569,14 @@ static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi,
return
&
intfd
->
endpoint
[
1
];
}
static
usb_endpoint_descriptor_t
*
snd_usbmidi_get_midiman_int_epd
(
snd_usb_midi_t
*
umidi
)
{
usb_interface_t
*
intf
=
umidi
->
iface
;
if
(
!
intf
)
return
NULL
;
return
&
intf
->
altsetting
[
0
].
endpoint
[
0
];
}
/*
* Creates an input endpoint, and initalizes input ports.
* ALSA ports are created later.
...
...
@@ -551,6 +600,9 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
for
(
i
=
0
;
i
<
0x10
;
++
i
)
ep
->
ports
[
i
].
seq_port
=
-
1
;
if
(
umidi
->
quirk
&&
umidi
->
quirk
->
type
==
QUIRK_MIDI_MIDIMAN
)
int_epd
=
snd_usbmidi_get_midiman_int_epd
(
umidi
);
else
int_epd
=
snd_usbmidi_get_int_epd
(
umidi
,
ep_info
->
epnum
);
ep
->
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
...
...
@@ -697,63 +749,63 @@ static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
}
/*
* After input and output endpoints have been initialized, create
* the ALSA port for each input/output port pair in the endpoint.
* *port_idx is the port number, which must be unique over all endpoints.
* Creates a sequencer port for an input/output cable pair.
*/
static
int
snd_usbmidi_create_endpoint_ports
(
snd_usb_midi_t
*
umidi
,
int
ep
,
int
*
port_idx
,
snd_usb_midi_endpoint_info_t
*
ep_info
)
static
int
snd_usbmidi_create_port
(
snd_usb_midi_t
*
umidi
,
snd_usb_midi_out_endpoint_t
*
out_ep
,
snd_usb_midi_in_endpoint_t
*
in_ep
,
int
cable
,
int
port_idx
)
{
int
c
,
err
;
int
cap
,
type
,
port
;
int
out
,
in
;
snd_seq_port_callback_t
port_callback
;
char
port_name
[
48
];
for
(
c
=
0
;
c
<
0x10
;
++
c
)
{
out
=
ep_info
->
out_cables
&
(
1
<<
c
);
in
=
ep_info
->
in_cables
&
(
1
<<
c
);
if
(
!
(
in
||
out
))
continue
;
cap
=
0
;
memset
(
&
port_callback
,
0
,
sizeof
(
port_callback
));
port_callback
.
owner
=
THIS_MODULE
;
if
(
out
)
{
if
(
out_ep
)
{
port_callback
.
event_input
=
snd_usbmidi_event_input
;
port_callback
.
private_data
=
&
umidi
->
endpoints
[
ep
].
out
->
ports
[
c
];
cap
|=
SNDRV_SEQ_PORT_CAP_WRITE
|
SNDRV_SEQ_PORT_CAP_SUBS_WRITE
;
port_callback
.
private_data
=
&
out_ep
->
ports
[
cable
];
cap
|=
SNDRV_SEQ_PORT_CAP_WRITE
|
SNDRV_SEQ_PORT_CAP_SUBS_WRITE
;
}
if
(
in
)
{
cap
|=
SNDRV_SEQ_PORT_CAP_READ
|
SNDRV_SEQ_PORT_CAP_SUBS_READ
;
if
(
in_ep
)
{
cap
|=
SNDRV_SEQ_PORT_CAP_READ
|
SNDRV_SEQ_PORT_CAP_SUBS_READ
;
}
if
(
out
&&
in
)
{
if
(
out_ep
&&
in_ep
)
{
cap
|=
SNDRV_SEQ_PORT_CAP_DUPLEX
;
}
/* TODO: read type bits from element descriptor */
type
=
SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
;
/* TODO: read port name from jack descriptor */
snprintf
(
port_name
,
sizeof
(
port_name
),
"%s Port %d"
,
umidi
->
chip
->
card
->
shortname
,
*
port_idx
);
port
=
snd_seq_event_port_attach
(
umidi
->
seq_client
,
&
port_callback
,
umidi
->
chip
->
card
->
shortname
,
port_idx
);
port
=
snd_seq_event_port_attach
(
umidi
->
seq_client
,
&
port_callback
,
cap
,
type
,
port_name
);
if
(
port
<
0
)
{
snd_printk
(
KERN_ERR
"cannot create port (error code %d)
\n
"
,
port
);
return
port
;
}
if
(
in
)
umidi
->
endpoints
[
ep
].
in
->
ports
[
c
].
seq_port
=
port
;
if
(
in_ep
)
in_ep
->
ports
[
cable
].
seq_port
=
port
;
return
port
;
}
if
(
*
port_idx
<
SNDRV_MINOR_RAWMIDIS
)
{
/*
* Creates a virmidi port emulating rawmidi for the sequencer port.
*/
static
int
snd_usbmidi_create_virmidi
(
snd_usb_midi_t
*
umidi
,
int
port
,
int
port_idx
,
snd_rawmidi_t
**
rrmidi
)
{
snd_rawmidi_t
*
rmidi
;
snd_virmidi_dev_t
*
rdev
;
err
=
snd_virmidi_new
(
umidi
->
chip
->
card
,
*
port_idx
,
&
rmidi
);
int
err
;
*
rrmidi
=
NULL
;
err
=
snd_virmidi_new
(
umidi
->
chip
->
card
,
port_idx
,
&
rmidi
);
if
(
err
<
0
)
return
err
;
sprintf
(
rmidi
->
name
,
"%s MIDI %d"
,
umidi
->
chip
->
card
->
shortname
,
port_idx
);
rdev
=
snd_magic_cast
(
snd_virmidi_dev_t
,
rmidi
->
private_data
,
return
-
ENXIO
);
strcpy
(
rmidi
->
name
,
port_name
);
rdev
->
seq_mode
=
SNDRV_VIRMIDI_SEQ_ATTACH
;
rdev
->
client
=
umidi
->
seq_client
;
rdev
->
port
=
port
;
...
...
@@ -762,7 +814,41 @@ static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi, int ep, int*
snd_device_free
(
umidi
->
chip
->
card
,
rmidi
);
return
err
;
}
umidi
->
endpoints
[
ep
].
rmidi
[
c
]
=
rmidi
;
*
rrmidi
=
rmidi
;
return
0
;
}
/*
* After input and output endpoints have been initialized, create
* the ALSA port for each input/output port pair in the endpoint.
* *port_idx is the port number, which must be unique over all endpoints.
*/
static
int
snd_usbmidi_create_endpoint_ports
(
snd_usb_midi_t
*
umidi
,
snd_usb_midi_endpoint_t
*
endpoint
,
int
*
port_idx
,
snd_usb_midi_endpoint_info_t
*
ep_info
)
{
int
cable
;
for
(
cable
=
0
;
cable
<
0x10
;
++
cable
)
{
int
port
,
err
;
int
out
=
ep_info
->
out_cables
&
(
1
<<
cable
);
int
in
=
ep_info
->
in_cables
&
(
1
<<
cable
);
if
(
!
(
in
||
out
))
continue
;
port
=
snd_usbmidi_create_port
(
umidi
,
out
?
endpoint
->
out
:
NULL
,
in
?
endpoint
->
in
:
NULL
,
cable
,
*
port_idx
);
if
(
port
<
0
)
return
port
;
if
(
*
port_idx
<
SNDRV_MINOR_RAWMIDIS
)
{
err
=
snd_usbmidi_create_virmidi
(
umidi
,
port
,
*
port_idx
,
&
endpoint
->
rmidi
[
cable
]);
if
(
err
<
0
)
return
err
;
}
++*
port_idx
;
}
...
...
@@ -792,8 +878,8 @@ static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
if
(
err
<
0
)
return
err
;
}
err
=
snd_usbmidi_create_endpoint_ports
(
umidi
,
i
,
&
port_idx
,
&
endpoints
[
i
]);
err
=
snd_usbmidi_create_endpoint_ports
(
umidi
,
&
umidi
->
endpoints
[
i
]
,
&
port_idx
,
&
endpoints
[
i
]);
if
(
err
<
0
)
return
err
;
printk
(
KERN_INFO
"snd-usb-midi: endpoint %d: created %d output and %d input ports
\n
"
,
...
...
@@ -817,9 +903,7 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
usb_ms_endpoint_descriptor_t
*
ms_ep
;
int
i
,
epidx
;
memset
(
endpoints
,
0
,
sizeof
(
*
endpoints
)
*
MIDI_MAX_ENDPOINTS
);
intf
=
local_usb_ifnum_to_if
(
umidi
->
chip
->
dev
,
umidi
->
ifnum
);
intf
=
umidi
->
iface
;
if
(
!
intf
)
return
-
ENXIO
;
intfd
=
&
intf
->
altsetting
[
0
];
...
...
@@ -878,7 +962,7 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
usb_endpoint_descriptor_t
*
epd
;
if
(
endpoint
->
epnum
==
-
1
)
{
intf
=
local_usb_ifnum_to_if
(
umidi
->
chip
->
dev
,
umidi
->
ifnum
)
;
intf
=
umidi
->
iface
;
if
(
!
intf
||
intf
->
num_altsetting
<
1
)
return
-
ENOENT
;
intfd
=
intf
->
altsetting
;
...
...
@@ -890,6 +974,120 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
return
0
;
}
/*
* Detects the endpoints and ports of Yamaha devices.
*/
static
int
snd_usbmidi_detect_yamaha
(
snd_usb_midi_t
*
umidi
,
snd_usb_midi_endpoint_info_t
*
endpoint
)
{
usb_interface_t
*
intf
;
usb_interface_descriptor_t
*
intfd
;
uint8_t
*
cs_desc
;
intf
=
umidi
->
iface
;
if
(
!
intf
)
return
-
ENOENT
;
intfd
=
intf
->
altsetting
;
if
(
intfd
->
bNumEndpoints
<
1
)
return
-
ENOENT
;
for
(
cs_desc
=
intfd
->
extra
;
cs_desc
<
intfd
->
extra
+
intfd
->
extralen
&&
cs_desc
[
0
]
>=
2
;
cs_desc
+=
cs_desc
[
0
])
{
if
(
cs_desc
[
1
]
==
CS_AUDIO_INTERFACE
)
{
if
(
cs_desc
[
2
]
==
MIDI_IN_JACK
)
endpoint
->
in_cables
=
(
endpoint
->
in_cables
<<
1
)
|
1
;
else
if
(
cs_desc
[
2
]
==
MIDI_OUT_JACK
)
endpoint
->
out_cables
=
(
endpoint
->
out_cables
<<
1
)
|
1
;
}
}
if
(
!
endpoint
->
in_cables
&&
!
endpoint
->
out_cables
)
return
-
ENOENT
;
endpoint
->
epnum
=
-
1
;
return
snd_usbmidi_detect_endpoint
(
umidi
,
endpoint
);
}
/*
* Creates the endpoints and their ports for Midiman devices.
*/
static
int
snd_usbmidi_create_endpoints_midiman
(
snd_usb_midi_t
*
umidi
,
int
ports
)
{
snd_usb_midi_endpoint_info_t
ep_info
;
usb_interface_t
*
intf
;
usb_interface_descriptor_t
*
intfd
;
usb_endpoint_descriptor_t
*
epd
;
int
cable
,
err
;
intf
=
umidi
->
iface
;
if
(
!
intf
)
return
-
ENOENT
;
intfd
=
intf
->
altsetting
;
if
(
intfd
->
bNumEndpoints
<
(
ports
>
1
?
5
:
3
))
{
snd_printdd
(
KERN_ERR
"not enough endpoints
\n
"
);
return
-
ENOENT
;
}
epd
=
&
intfd
->
endpoint
[
0
];
if
((
epd
->
bEndpointAddress
&
USB_ENDPOINT_DIR_MASK
)
!=
USB_DIR_IN
||
(
epd
->
bmAttributes
&
USB_ENDPOINT_XFERTYPE_MASK
)
!=
USB_ENDPOINT_XFER_INT
)
{
snd_printdd
(
KERN_ERR
"endpoint[0] isn't interrupt
\n
"
);
return
-
ENXIO
;
}
epd
=
&
intfd
->
endpoint
[
2
];
if
((
epd
->
bEndpointAddress
&
USB_ENDPOINT_DIR_MASK
)
!=
USB_DIR_OUT
||
(
epd
->
bmAttributes
&
USB_ENDPOINT_XFERTYPE_MASK
)
!=
USB_ENDPOINT_XFER_BULK
)
{
snd_printdd
(
KERN_ERR
"endpoint[2] isn't bulk output
\n
"
);
return
-
ENXIO
;
}
if
(
ports
>
1
)
{
epd
=
&
intfd
->
endpoint
[
4
];
if
((
epd
->
bEndpointAddress
&
USB_ENDPOINT_DIR_MASK
)
!=
USB_DIR_OUT
||
(
epd
->
bmAttributes
&
USB_ENDPOINT_XFERTYPE_MASK
)
!=
USB_ENDPOINT_XFER_BULK
)
{
snd_printdd
(
KERN_ERR
"endpoint[4] isn't bulk output
\n
"
);
return
-
ENXIO
;
}
}
ep_info
.
epnum
=
intfd
->
endpoint
[
2
].
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
ep_info
.
out_cables
=
0x5555
&
((
1
<<
ports
)
-
1
);
err
=
snd_usbmidi_out_endpoint_create
(
umidi
,
&
ep_info
,
&
umidi
->
endpoints
[
0
]);
if
(
err
<
0
)
return
err
;
ep_info
.
epnum
=
intfd
->
endpoint
[
0
].
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
ep_info
.
in_cables
=
(
1
<<
ports
)
-
1
;
err
=
snd_usbmidi_in_endpoint_create
(
umidi
,
&
ep_info
,
&
umidi
->
endpoints
[
0
]);
if
(
err
<
0
)
return
err
;
umidi
->
endpoints
[
0
].
in
->
urb
->
complete
=
snd_usbmidi_in_midiman_complete
;
if
(
ports
>
1
)
{
ep_info
.
epnum
=
intfd
->
endpoint
[
4
].
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
;
ep_info
.
out_cables
=
0xaaaa
&
((
1
<<
ports
)
-
1
);
err
=
snd_usbmidi_out_endpoint_create
(
umidi
,
&
ep_info
,
&
umidi
->
endpoints
[
1
]);
if
(
err
<
0
)
return
err
;
}
for
(
cable
=
0
;
cable
<
ports
;
++
cable
)
{
int
port
=
snd_usbmidi_create_port
(
umidi
,
umidi
->
endpoints
[
cable
&
1
].
out
,
umidi
->
endpoints
[
0
].
in
,
cable
,
cable
);
if
(
port
<
0
)
return
port
;
if
(
cable
<
SNDRV_MINOR_RAWMIDIS
)
{
int
err
=
snd_usbmidi_create_virmidi
(
umidi
,
port
,
cable
,
&
umidi
->
endpoints
[
0
].
rmidi
[
cable
]);
if
(
err
<
0
)
return
err
;
}
}
return
0
;
}
/*
* Initialize the sequencer device.
*/
...
...
@@ -912,6 +1110,7 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
if
(
umidi
->
seq_client
<
0
)
return
umidi
->
seq_client
;
/* set the client name */
memset
(
&
client_info
,
0
,
sizeof
(
client_info
));
client_info
.
client
=
umidi
->
seq_client
;
client_info
.
type
=
KERNEL_CLIENT
;
...
...
@@ -935,17 +1134,37 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
SNDRV_SEQ_IOCTL_SET_CLIENT_INFO
,
&
client_info
);
if
(
umidi
->
quirk
)
{
memcpy
(
endpoints
,
umidi
->
quirk
->
endpoints
,
sizeof
(
endpoints
));
err
=
snd_usbmidi_detect_endpoint
(
umidi
,
&
endpoints
[
0
]);
}
else
{
/* detect the endpoint(s) to use */
memset
(
endpoints
,
0
,
sizeof
(
endpoints
));
if
(
!
umidi
->
quirk
)
{
err
=
snd_usbmidi_get_ms_info
(
umidi
,
endpoints
);
}
else
{
switch
(
umidi
->
quirk
->
type
)
{
case
QUIRK_MIDI_FIXED_ENDPOINT
:
memcpy
(
&
endpoints
[
0
],
umidi
->
quirk
->
data
,
sizeof
(
snd_usb_midi_endpoint_info_t
));
err
=
snd_usbmidi_detect_endpoint
(
umidi
,
&
endpoints
[
0
]);
break
;
case
QUIRK_MIDI_YAMAHA
:
err
=
snd_usbmidi_detect_yamaha
(
umidi
,
&
endpoints
[
0
]);
break
;
case
QUIRK_MIDI_MIDIMAN
:
err
=
0
;
break
;
default:
snd_printd
(
KERN_ERR
"invalid quirk type %d
\n
"
,
umidi
->
quirk
->
type
);
err
=
-
ENXIO
;
break
;
}
if
(
err
<
0
)
{
snd_usbmidi_seq_device_delete
(
seq_device
);
return
err
;
}
/* create ports */
if
(
err
>=
0
)
{
if
(
umidi
->
quirk
&&
umidi
->
quirk
->
type
==
QUIRK_MIDI_MIDIMAN
)
err
=
snd_usbmidi_create_endpoints_midiman
(
umidi
,
(
int
)
umidi
->
quirk
->
data
);
else
err
=
snd_usbmidi_create_endpoints
(
umidi
,
endpoints
);
}
if
(
err
<
0
)
{
snd_usbmidi_seq_device_delete
(
seq_device
);
return
err
;
...
...
sound/usb/usbquirks.h
View file @
9fd6aa65
...
...
@@ -26,45 +26,143 @@
* In a perfect world, this file would be empty.
*/
#define USB_DEVICE_VENDOR_SPEC(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | \
USB_DEVICE_ID_MATCH_PRODUCT | \
USB_DEVICE_ID_MATCH_INT_CLASS, \
.idVendor = vend, \
.idProduct = prod, \
.bInterfaceClass = USB_CLASS_VENDOR_SPEC
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
/* Yamaha devices */
{
/* from NetBSD's umidi driver */
USB_DEVICE
(
0x0499
,
0x1000
),
/* Yamaha UX256 */
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1000
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
ifnum
=
0
,
.
endpoints
=
{
{
.
epnum
=
-
1
,
.
out_cables
=
0xffff
,
.
in_cables
=
0x00ff
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"UX256"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1001
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"MU1000"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1002
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"MU2000"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
/* from Nagano Daisuke's usb-midi driver */
USB_DEVICE
(
0x0499
,
0x1001
),
/* Yamaha MU1000 */
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1003
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
ifnum
=
0
,
.
endpoints
=
{
{
.
epnum
=
1
,
.
out_cables
=
0x000f
,
.
in_cables
=
0x0001
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"MU500"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1004
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"UW500"
,
.
ifnum
=
3
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1005
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"MOTIF6"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1006
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"MOTIF7"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1007
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"MOTIF8"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1008
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"UX96"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1009
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"UX16"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x100a
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"EOS BX"
,
.
ifnum
=
3
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x100e
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"S08"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x100f
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"CLP-150"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0499
,
0x1010
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Yamaha"
,
.
product_name
=
"CLP-170"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_YAMAHA
}
},
/*
* I don't know whether the following Yamaha devices need entries or not:
* 0x1002 MU2000 0x1008 UX96
* 0x1003 MU500 0x1009 UX16
* 0x1004 UW500 0x100e S08
* 0x1005 MOTIF6 0x100f CLP-150
* 0x1006 MOTIF7 0x1010 CLP-170
* 0x1007 MOTIF8
*/
/*
* Once upon a time people thought, "Wouldn't it be nice if there was a
...
...
@@ -79,259 +177,316 @@
* class-specific descriptors.
*/
{
USB_DEVICE
(
0x0582
,
0x0000
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0000
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"UA-100"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0007
,
.
in_cables
=
0x0007
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0002
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0002
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"UM-4"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x000f
,
.
in_cables
=
0x000f
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0003
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0003
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"SC-8850"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x003f
,
.
in_cables
=
0x003f
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0004
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0004
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"U-8"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0003
,
.
in_cables
=
0x0003
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0005
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0005
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"UM-2"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0003
,
.
in_cables
=
0x0003
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0007
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0007
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"SC-8820"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0013
,
.
in_cables
=
0x0013
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0008
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0008
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"PC-300"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0001
,
.
in_cables
=
0x0001
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0009
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0009
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"UM-1"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0001
,
.
in_cables
=
0x0001
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x000b
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x000b
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"SK-500"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0013
,
.
in_cables
=
0x0013
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x000c
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x000c
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"SC-D70"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0007
,
.
in_cables
=
0x0007
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0012
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0012
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"XV-5050"
,
.
ifnum
=
0
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0001
,
.
in_cables
=
0x0001
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0014
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0014
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"UM-880"
,
.
ifnum
=
0
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x01ff
,
.
in_cables
=
0x01ff
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0016
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0016
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"SD-90"
,
.
ifnum
=
2
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x000f
,
.
in_cables
=
0x000f
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0023
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0023
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"UM-550"
,
.
ifnum
=
0
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x003f
,
.
in_cables
=
0x003f
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0027
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0027
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"SD-20"
,
.
ifnum
=
0
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0003
,
.
in_cables
=
0x0007
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x0029
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x0029
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"SD-80"
,
.
ifnum
=
0
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x000f
,
.
in_cables
=
0x000f
}
}
}
},
{
USB_DEVICE
(
0x0582
,
0x002b
),
USB_DEVICE
_VENDOR_SPEC
(
0x0582
,
0x002b
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"EDIROL"
,
.
product_name
=
"UA-700"
,
.
ifnum
=
3
,
.
endpoints
=
{
{
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
snd_usb_midi_endpoint_info_t
)
{
.
epnum
=
-
1
,
.
out_cables
=
0x0003
,
.
in_cables
=
0x0003
}
}
},
/* Midiman/M-Audio devices */
{
USB_DEVICE_VENDOR_SPEC
(
0x0763
,
0x1002
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"M-Audio"
,
.
product_name
=
"MidiSport 2x2"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_MIDIMAN
,
.
data
=
(
void
*
)
2
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0763
,
0x1011
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"M-Audio"
,
.
product_name
=
"MidiSport 1x1"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_MIDIMAN
,
.
data
=
(
void
*
)
1
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0763
,
0x1015
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"M-Audio"
,
.
product_name
=
"Keystation"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_MIDIMAN
,
.
data
=
(
void
*
)
1
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0763
,
0x1021
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"M-Audio"
,
.
product_name
=
"MidiSport 4x4"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_MIDIMAN
,
.
data
=
(
void
*
)
4
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0763
,
0x1033
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"M-Audio"
,
.
product_name
=
"MidiSport 8x8"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_MIDI_MIDIMAN
,
.
data
=
(
void
*
)
9
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0763
,
0x2001
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"M-Audio"
,
.
product_name
=
"Quattro"
,
.
ifnum
=
9
,
.
type
=
QUIRK_MIDI_MIDIMAN
,
.
data
=
(
void
*
)
1
}
},
{
USB_DEVICE_VENDOR_SPEC
(
0x0763
,
0x2003
),
.
driver_info
=
(
unsigned
long
)
&
(
const
snd_usb_audio_quirk_t
)
{
.
vendor_name
=
"M-Audio"
,
.
product_name
=
"AudioPhile"
,
.
ifnum
=
9
,
.
type
=
QUIRK_MIDI_MIDIMAN
,
.
data
=
(
void
*
)
1
}
},
#endif
/* CONFIG_SND_SEQUENCER(_MODULE) */
#undef USB_DEVICE_VENDOR_SPEC
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment