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
ac1d5c67
Commit
ac1d5c67
authored
Oct 22, 2002
by
Jaroslav Kysela
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ALSA update
- usb midi driver rewritten to use rawmidi interface
parent
02bb5f56
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
388 additions
and
587 deletions
+388
-587
sound/usb/Makefile
sound/usb/Makefile
+1
-7
sound/usb/usbaudio.c
sound/usb/usbaudio.c
+0
-31
sound/usb/usbaudio.h
sound/usb/usbaudio.h
+3
-30
sound/usb/usbmidi.c
sound/usb/usbmidi.c
+384
-519
No files found.
sound/usb/Makefile
View file @
ac1d5c67
...
...
@@ -2,15 +2,9 @@
# Makefile for ALSA
#
snd-usb-audio-objs
:=
usbaudio.o usbmixer.o
ifeq
($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
snd-usb-midi-objs
:=
usbmidi.o
endif
snd-usb-audio-objs
:=
usbaudio.o usbmixer.o usbmidi.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_USB_AUDIO)
+=
snd-usb-audio.o
ifeq
($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
obj-$(CONFIG_SND_USB_AUDIO)
+=
snd-usb-midi.o
endif
include
$(TOPDIR)/Rules.make
sound/usb/usbaudio.c
View file @
ac1d5c67
...
...
@@ -1833,11 +1833,6 @@ 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
,
struct
usb_interface
*
iface
,
const
snd_usb_audio_quirk_t
*
quirk
);
static
int
snd_usb_create_streams
(
snd_usb_audio_t
*
chip
,
int
ctrlif
,
unsigned
char
*
buffer
,
int
buflen
)
{
...
...
@@ -1896,32 +1891,6 @@ 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
,
struct
usb_interface
*
iface
,
const
snd_usb_audio_quirk_t
*
quirk
)
{
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
snd_seq_device_t
*
seq_device
;
snd_usb_midi_t
*
umidi
;
int
err
;
err
=
snd_seq_device_new
(
chip
->
card
,
chip
->
next_seq_device
,
SNDRV_SEQ_DEV_ID_USBMIDI
,
sizeof
(
snd_usb_midi_t
),
&
seq_device
);
if
(
err
<
0
)
return
err
;
chip
->
next_seq_device
++
;
strcpy
(
seq_device
->
name
,
chip
->
card
->
shortname
);
umidi
=
(
snd_usb_midi_t
*
)
SNDRV_SEQ_DEVICE_ARGPTR
(
seq_device
);
umidi
->
chip
=
chip
;
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
,
struct
usb_interface
*
iface
,
const
snd_usb_audio_quirk_t
*
quirk
)
...
...
sound/usb/usbaudio.h
View file @
ac1d5c67
...
...
@@ -123,8 +123,6 @@
/* maximum number of endpoints per interface */
#define MIDI_MAX_ENDPOINTS 2
#define SNDRV_SEQ_DEV_ID_USBMIDI "usb-midi"
/*
*/
...
...
@@ -140,9 +138,7 @@ struct snd_usb_audio {
struct
list_head
pcm_list
;
/* list of pcm streams */
int
pcm_devs
;
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
int
next_seq_device
;
#endif
int
next_midi_device
;
};
/*
...
...
@@ -176,31 +172,6 @@ struct snd_usb_midi_endpoint_info {
/* for QUIRK_MIDI_MIDIMAN, data is the number of ports */
/*
* USB MIDI sequencer device data
*/
typedef
struct
snd_usb_midi
snd_usb_midi_t
;
typedef
struct
snd_usb_midi_endpoint
snd_usb_midi_endpoint_t
;
typedef
struct
snd_usb_midi_out_endpoint
snd_usb_midi_out_endpoint_t
;
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
;
/* used internally in usbmidi.c */
int
seq_client
;
struct
snd_usb_midi_endpoint
{
snd_usb_midi_out_endpoint_t
*
out
;
snd_usb_midi_in_endpoint_t
*
in
;
snd_rawmidi_t
*
rmidi
[
0x10
];
}
endpoints
[
MIDI_MAX_ENDPOINTS
];
};
/*
*/
...
...
@@ -215,4 +186,6 @@ void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsub
int
snd_usb_create_mixer
(
snd_usb_audio_t
*
chip
,
int
ctrlif
,
unsigned
char
*
buffer
,
int
buflen
);
int
snd_usb_create_midi_interface
(
snd_usb_audio_t
*
chip
,
struct
usb_interface
*
iface
,
const
snd_usb_audio_quirk_t
*
quirk
);
#endif
/* __USBAUDIO_H */
sound/usb/usbmidi.c
View file @
ac1d5c67
...
...
@@ -46,34 +46,9 @@
#include <linux/usb.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/asequencer.h>
#include <sound/seq_device.h>
#include <sound/seq_kernel.h>
#include <sound/seq_virmidi.h>
#include <sound/seq_midi_event.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
#include "usbaudio.h"
MODULE_AUTHOR
(
"Clemens Ladisch <clemens@ladisch.de>"
);
MODULE_DESCRIPTION
(
"USB MIDI"
);
MODULE_LICENSE
(
"Dual BSD/GPL"
);
MODULE_CLASSES
(
"{sound}"
);
/* size of the per-endpoint output buffer, must be a multiple of 4 */
#define OUTPUT_BUFFER_SIZE 0x400
/* max. size of incoming sysex messages */
#define INPUT_BUFFER_SIZE 0x200
typedef
struct
usb_driver
usb_driver_t
;
typedef
struct
usb_device
usb_device_t
;
typedef
struct
usb_device_id
usb_device_id_t
;
typedef
struct
usb_interface
usb_interface_t
;
typedef
struct
usb_interface_descriptor
usb_interface_descriptor_t
;
typedef
struct
usb_ms_header_descriptor
usb_ms_header_descriptor_t
;
typedef
struct
usb_endpoint_descriptor
usb_endpoint_descriptor_t
;
typedef
struct
usb_ms_endpoint_descriptor
usb_ms_endpoint_descriptor_t
;
struct
usb_ms_header_descriptor
{
__u8
bLength
;
__u8
bDescriptorType
;
...
...
@@ -90,35 +65,56 @@ struct usb_ms_endpoint_descriptor {
__u8
baAssocJackID
[
0
];
}
__attribute__
((
packed
));
typedef
struct
snd_usb_midi
snd_usb_midi_t
;
typedef
struct
snd_usb_midi_endpoint
snd_usb_midi_endpoint_t
;
typedef
struct
snd_usb_midi_out_endpoint
snd_usb_midi_out_endpoint_t
;
typedef
struct
snd_usb_midi_in_endpoint
snd_usb_midi_in_endpoint_t
;
typedef
struct
usbmidi_out_port
usbmidi_out_port_t
;
typedef
struct
usbmidi_in_port
usbmidi_in_port_t
;
struct
snd_usb_midi
{
snd_usb_audio_t
*
chip
;
struct
usb_interface
*
iface
;
const
snd_usb_audio_quirk_t
*
quirk
;
snd_rawmidi_t
*
rmidi
;
struct
snd_usb_midi_endpoint
{
snd_usb_midi_out_endpoint_t
*
out
;
snd_usb_midi_in_endpoint_t
*
in
;
}
endpoints
[
MIDI_MAX_ENDPOINTS
];
};
struct
snd_usb_midi_out_endpoint
{
snd_usb_midi_t
*
umidi
;
struct
urb
*
urb
;
int
max_transfer
;
/* size of urb buffer */
struct
tasklet_struct
tasklet
;
uint8_t
buffer
[
OUTPUT_BUFFER_SIZE
];
/* ring buffer */
int
data_begin
;
int
data_size
;
spinlock_t
buffer_lock
;
struct
usbmidi_out_port
{
snd_usb_midi_out_endpoint_t
*
ep
;
snd_rawmidi_substream_t
*
substream
;
int
active
;
uint8_t
cable
;
/* cable number << 4 */
uint8_t
sysex_len
;
uint8_t
sysex
[
2
];
uint8_t
state
;
#define STATE_UNKNOWN 0
#define STATE_1PARAM 1
#define STATE_2PARAM_1 2
#define STATE_2PARAM_2 3
#define STATE_SYSEX_0 4
#define STATE_SYSEX_1 5
#define STATE_SYSEX_2 6
uint8_t
data
[
2
];
}
ports
[
0x10
];
};
struct
snd_usb_midi_in_endpoint
{
snd_usb_midi_t
*
umidi
;
snd_usb_midi_endpoint_t
*
ep
;
struct
urb
*
urb
;
struct
usbmidi_in_port
{
int
seq_port
;
snd_midi_event_t
*
midi_event
;
snd_rawmidi_substream_t
*
substream
;
int
active
;
}
ports
[
0x10
];
};
...
...
@@ -155,28 +151,18 @@ static int snd_usbmidi_urb_error(int status)
}
/*
*
Converts a USB MIDI packet into an ALSA sequencer even
t.
*
Receives a USB MIDI packe
t.
*/
static
void
snd_usbmidi_input_packet
(
snd_usb_midi_in_endpoint_t
*
ep
,
uint8_t
packet
[
4
])
{
int
cable
=
packet
[
0
]
>>
4
;
usbmidi_in_port_t
*
port
=
&
ep
->
ports
[
cable
];
snd_seq_event_t
ev
;
if
(
!
port
->
midi_event
)
if
(
!
port
->
active
)
return
;
memset
(
&
ev
,
0
,
sizeof
(
ev
));
if
(
snd_midi_event_encode
(
port
->
midi_event
,
&
packet
[
1
],
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
;
snd_seq_kernel_client_dispatch
(
ep
->
umidi
->
seq_client
,
&
ev
,
1
,
0
);
if
(
ep
->
ep
->
rmidi
[
cable
])
snd_virmidi_receive
(
ep
->
ep
->
rmidi
[
cable
],
&
ev
);
}
snd_rawmidi_receive
(
port
->
substream
,
&
packet
[
1
],
snd_usbmidi_cin_length
[
packet
[
0
]
&
0x0f
]);
}
/*
...
...
@@ -239,15 +225,12 @@ static void snd_usbmidi_in_midiman_complete(struct urb* 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
);
unsigned
long
flags
;
if
(
urb
->
status
<
0
)
{
if
(
snd_usbmidi_urb_error
(
urb
->
status
)
<
0
)
return
;
}
spin_lock_irqsave
(
&
ep
->
buffer_lock
,
flags
);
snd_usbmidi_do_output
(
ep
);
spin_unlock_irqrestore
(
&
ep
->
buffer_lock
,
flags
);
}
/*
...
...
@@ -267,262 +250,256 @@ static void snd_usbmidi_convert_to_midiman(struct urb* urb)
}
}
/*
* Adds one USB MIDI packet to the output buffer.
*/
static
inline
void
output_packet
(
struct
urb
*
urb
,
uint8_t
p0
,
uint8_t
p1
,
uint8_t
p2
,
uint8_t
p3
)
{
uint8_t
*
buf
=
(
uint8_t
*
)
urb
->
transfer_buffer
+
urb
->
transfer_buffer_length
;
buf
[
0
]
=
p0
;
buf
[
1
]
=
p1
;
buf
[
2
]
=
p2
;
buf
[
3
]
=
p3
;
urb
->
transfer_buffer_length
+=
4
;
}
/*
* Converts MIDI commands to USB MIDI packets.
*/
static
void
snd_usbmidi_transmit_byte
(
usbmidi_out_port_t
*
port
,
uint8_t
b
,
struct
urb
*
urb
)
{
uint8_t
p0
=
port
->
cable
;
if
(
b
>=
0xf8
)
{
output_packet
(
urb
,
p0
|
0x0f
,
b
,
0
,
0
);
}
else
if
(
b
>=
0xf0
)
{
switch
(
b
)
{
case
0xf0
:
port
->
data
[
0
]
=
b
;
port
->
state
=
STATE_SYSEX_1
;
break
;
case
0xf1
:
case
0xf3
:
port
->
data
[
0
]
=
b
;
port
->
state
=
STATE_1PARAM
;
break
;
case
0xf2
:
port
->
data
[
0
]
=
b
;
port
->
state
=
STATE_2PARAM_1
;
break
;
case
0xf4
:
case
0xf5
:
port
->
state
=
STATE_UNKNOWN
;
break
;
case
0xf6
:
output_packet
(
urb
,
p0
|
0x05
,
0xf6
,
0
,
0
);
port
->
state
=
STATE_UNKNOWN
;
break
;
case
0xf7
:
switch
(
port
->
state
)
{
case
STATE_SYSEX_0
:
output_packet
(
urb
,
p0
|
0x05
,
0xf7
,
0
,
0
);
break
;
case
STATE_SYSEX_1
:
output_packet
(
urb
,
p0
|
0x06
,
port
->
data
[
0
],
0xf7
,
0
);
break
;
case
STATE_SYSEX_2
:
output_packet
(
urb
,
p0
|
0x07
,
port
->
data
[
0
],
port
->
data
[
1
],
0xf7
);
break
;
}
port
->
state
=
STATE_UNKNOWN
;
break
;
}
}
else
if
(
b
>=
0x80
)
{
port
->
data
[
0
]
=
b
;
if
(
b
>=
0xc0
&&
b
<=
0xdf
)
port
->
state
=
STATE_1PARAM
;
else
port
->
state
=
STATE_2PARAM_1
;
}
else
{
/* b < 0x80 */
switch
(
port
->
state
)
{
case
STATE_1PARAM
:
if
(
port
->
data
[
0
]
<
0xf0
)
{
p0
|=
port
->
data
[
0
]
>>
4
;
}
else
{
p0
|=
0x02
;
port
->
state
=
STATE_UNKNOWN
;
}
output_packet
(
urb
,
p0
,
port
->
data
[
0
],
b
,
0
);
break
;
case
STATE_2PARAM_1
:
port
->
data
[
1
]
=
b
;
port
->
state
=
STATE_2PARAM_2
;
break
;
case
STATE_2PARAM_2
:
if
(
port
->
data
[
0
]
<
0xf0
)
{
p0
|=
port
->
data
[
0
]
>>
4
;
port
->
state
=
STATE_2PARAM_1
;
}
else
{
p0
|=
0x03
;
port
->
state
=
STATE_UNKNOWN
;
}
output_packet
(
urb
,
p0
,
port
->
data
[
0
],
port
->
data
[
1
],
b
);
break
;
case
STATE_SYSEX_0
:
port
->
data
[
0
]
=
b
;
port
->
state
=
STATE_SYSEX_1
;
break
;
case
STATE_SYSEX_1
:
port
->
data
[
1
]
=
b
;
port
->
state
=
STATE_SYSEX_2
;
break
;
case
STATE_SYSEX_2
:
output_packet
(
urb
,
p0
|
0x04
,
port
->
data
[
0
],
port
->
data
[
1
],
b
);
port
->
state
=
STATE_SYSEX_0
;
break
;
}
}
}
/*
* Moves data from one substream buffer to the URB transfer buffer.
*/
static
void
snd_usbmidi_transmit
(
snd_usb_midi_out_endpoint_t
*
ep
,
int
port_idx
)
{
struct
urb
*
urb
=
ep
->
urb
;
usbmidi_out_port_t
*
port
=
&
ep
->
ports
[
port_idx
];
while
(
urb
->
transfer_buffer_length
<
ep
->
max_transfer
)
{
uint8_t
b
;
if
(
snd_rawmidi_transmit_peek
(
port
->
substream
,
&
b
,
1
)
!=
1
)
{
port
->
active
=
0
;
break
;
}
snd_usbmidi_transmit_byte
(
port
,
b
,
urb
);
snd_rawmidi_transmit_ack
(
port
->
substream
,
1
);
}
}
/*
* This is called when some data should be transferred to the device
* (after the reception of one or more sequencer events, or after completion
* of the previous transfer). ep->buffer_lock must be held.
* (from one or more substreams).
*/
static
void
snd_usbmidi_do_output
(
snd_usb_midi_out_endpoint_t
*
ep
)
{
int
len
;
uint8_t
*
buffer
;
if
(
ep
->
urb
->
status
==
-
EINPROGRESS
||
ep
->
data_size
==
0
)
int
p
;
struct
urb
*
urb
=
ep
->
urb
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
ep
->
buffer_lock
,
flags
);
if
(
urb
->
status
==
-
EINPROGRESS
)
{
spin_unlock_irqrestore
(
&
ep
->
buffer_lock
,
flags
);
return
;
buffer
=
(
uint8_t
*
)
ep
->
urb
->
transfer_buffer
;
/* first chunk, up to the end of the buffer */
len
=
OUTPUT_BUFFER_SIZE
-
ep
->
data_begin
;
if
(
len
>
ep
->
data_size
)
len
=
ep
->
data_size
;
if
(
len
>
ep
->
max_transfer
)
len
=
ep
->
max_transfer
;
if
(
len
>
0
)
{
memcpy
(
buffer
,
ep
->
buffer
+
ep
->
data_begin
,
len
);
ep
->
data_begin
=
(
ep
->
data_begin
+
len
)
%
OUTPUT_BUFFER_SIZE
;
ep
->
data_size
-=
len
;
buffer
+=
len
;
ep
->
urb
->
transfer_buffer_length
=
len
;
}
/* second chunk (after wraparound) */
if
(
ep
->
data_begin
==
0
&&
ep
->
data_size
>
0
&&
len
<
ep
->
max_transfer
)
{
len
=
ep
->
max_transfer
-
len
;
if
(
len
>
ep
->
data_size
)
len
=
ep
->
data_size
;
memcpy
(
buffer
,
ep
->
buffer
,
len
);
ep
->
data_begin
=
len
;
ep
->
data_size
-=
len
;
ep
->
urb
->
transfer_buffer_length
+=
len
;
}
urb
->
transfer_buffer_length
=
0
;
for
(
p
=
0
;
p
<
0x10
;
++
p
)
if
(
ep
->
ports
[
p
].
active
)
snd_usbmidi_transmit
(
ep
,
p
);
if
(
len
>
0
)
{
if
(
urb
->
transfer_buffer_length
>
0
)
{
if
(
ep
->
umidi
->
quirk
&&
ep
->
umidi
->
quirk
->
type
==
QUIRK_MIDI_MIDIMAN
)
snd_usbmidi_convert_to_midiman
(
ep
->
urb
);
snd_usbmidi_convert_to_midiman
(
urb
);
ep
->
urb
->
dev
=
ep
->
umidi
->
chip
->
dev
;
snd_usbmidi_submit_urb
(
ep
->
urb
,
GFP_ATOMIC
);
urb
->
dev
=
ep
->
umidi
->
chip
->
dev
;
snd_usbmidi_submit_urb
(
urb
,
GFP_ATOMIC
);
}
spin_unlock_irqrestore
(
&
ep
->
buffer_lock
,
flags
);
}
static
void
snd_usbmidi_out_tasklet
(
unsigned
long
data
)
{
snd_usb_midi_out_endpoint_t
*
ep
=
snd_magic_cast
(
snd_usb_midi_out_endpoint_t
,
(
void
*
)
data
,
return
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
ep
->
buffer_lock
,
flags
);
snd_usbmidi_do_output
(
ep
);
spin_unlock_irqrestore
(
&
ep
->
buffer_lock
,
flags
);
}
/*
* Adds one USB MIDI packet to the output buffer.
*/
static
void
output_packet
(
usbmidi_out_port_t
*
port
,
uint8_t
p0
,
uint8_t
p1
,
uint8_t
p2
,
uint8_t
p3
)
static
int
snd_usbmidi_output_open
(
snd_rawmidi_substream_t
*
substream
)
{
snd_usb_midi_out_endpoint_t
*
ep
=
port
->
ep
;
unsigned
long
flags
;
snd_usb_midi_t
*
umidi
=
snd_magic_cast
(
snd_usb_midi_t
,
substream
->
rmidi
->
private_data
,
return
-
ENXIO
);
usbmidi_out_port_t
*
port
=
NULL
;
int
i
,
j
;
spin_lock_irqsave
(
&
ep
->
buffer_lock
,
flags
);
if
(
ep
->
data_size
<
OUTPUT_BUFFER_SIZE
)
{
uint8_t
*
buf
=
ep
->
buffer
+
(
ep
->
data_begin
+
ep
->
data_size
)
%
OUTPUT_BUFFER_SIZE
;
buf
[
0
]
=
p0
;
buf
[
1
]
=
p1
;
buf
[
2
]
=
p2
;
buf
[
3
]
=
p3
;
ep
->
data_size
+=
4
;
if
(
ep
->
data_size
==
ep
->
max_transfer
)
snd_usbmidi_do_output
(
ep
)
;
}
spin_unlock_irqrestore
(
&
ep
->
buffer_lock
,
flags
)
;
for
(
i
=
0
;
i
<
MIDI_MAX_ENDPOINTS
;
++
i
)
if
(
umidi
->
endpoints
[
i
].
out
)
for
(
j
=
0
;
j
<
0x10
;
++
j
)
if
(
umidi
->
endpoints
[
i
].
out
->
ports
[
j
].
substream
==
substream
)
{
port
=
&
umidi
->
endpoints
[
i
].
out
->
ports
[
j
]
;
break
;
}
if
(
!
port
)
return
-
ENXIO
;
substream
->
runtime
->
private_data
=
port
;
port
->
state
=
STATE_UNKNOWN
;
return
0
;
}
/*
* Callback for snd_seq_dump_var_event.
*/
static
int
snd_usbmidi_sysex_dump
(
void
*
ptr
,
void
*
buf
,
int
count
)
static
int
snd_usbmidi_output_close
(
snd_rawmidi_substream_t
*
substream
)
{
usbmidi_out_port_t
*
port
=
(
usbmidi_out_port_t
*
)
ptr
;
const
uint8_t
*
dump
=
(
const
uint8_t
*
)
buf
;
for
(;
count
;
--
count
)
{
uint8_t
byte
=
*
dump
++
;
if
(
byte
==
0xf0
&&
port
->
sysex_len
>
0
)
{
/*
* The previous SysEx wasn't terminated correctly.
* Send the last bytes anyway, and hope that the
* receiving device won't be too upset about the
* missing F7.
*/
output_packet
(
port
,
port
->
cable
|
(
0x04
+
port
->
sysex_len
),
port
->
sysex
[
0
],
port
->
sysex_len
>=
2
?
port
->
sysex
[
1
]
:
0
,
0
);
port
->
sysex_len
=
0
;
}
if
(
byte
!=
0xf7
)
{
if
(
port
->
sysex_len
>=
2
)
{
output_packet
(
port
,
port
->
cable
|
0x04
,
port
->
sysex
[
0
],
port
->
sysex
[
1
],
byte
);
port
->
sysex_len
=
0
;
}
else
{
port
->
sysex
[
port
->
sysex_len
++
]
=
byte
;
}
}
else
{
uint8_t
cin
,
data
[
3
];
int
i
;
for
(
i
=
0
;
i
<
port
->
sysex_len
;
++
i
)
data
[
i
]
=
port
->
sysex
[
i
];
data
[
i
++
]
=
0xf7
;
cin
=
port
->
cable
|
(
0x04
+
i
);
for
(;
i
<
3
;
++
i
)
data
[
i
]
=
0
;
/*
* cin,data[] is x5,{F7 00 00}
* or x6,{xx F7 00}
* or x7,{xx xx F7}
*/
output_packet
(
port
,
cin
,
data
[
0
],
data
[
1
],
data
[
2
]);
port
->
sysex_len
=
0
;
}
}
return
0
;
}
/*
* Converts an ALSA sequencer event into USB MIDI packets.
*/
static
int
snd_usbmidi_event_input
(
snd_seq_event_t
*
ev
,
int
direct
,
void
*
private_data
,
int
atomic
,
int
hop
)
static
void
snd_usbmidi_output_trigger
(
snd_rawmidi_substream_t
*
substream
,
int
up
)
{
usbmidi_out_port_t
*
port
=
(
usbmidi_out_port_t
*
)
private_data
;
int
err
;
uint8_t
p0
,
p1
;
p0
=
port
->
cable
;
p1
=
ev
->
data
.
note
.
channel
&
0xf
;
switch
(
ev
->
type
)
{
case
SNDRV_SEQ_EVENT_NOTEON
:
output_packet
(
port
,
p0
|
0x09
,
p1
|
0x90
,
ev
->
data
.
note
.
note
&
0x7f
,
ev
->
data
.
note
.
velocity
&
0x7f
);
break
;
case
SNDRV_SEQ_EVENT_NOTEOFF
:
output_packet
(
port
,
p0
|
0x08
,
p1
|
0x80
,
ev
->
data
.
note
.
note
&
0x7f
,
ev
->
data
.
note
.
velocity
&
0x7f
);
break
;
case
SNDRV_SEQ_EVENT_KEYPRESS
:
output_packet
(
port
,
p0
|
0x0a
,
p1
|
0xa0
,
ev
->
data
.
note
.
note
&
0x7f
,
ev
->
data
.
note
.
velocity
&
0x7f
);
break
;
case
SNDRV_SEQ_EVENT_CONTROLLER
:
output_packet
(
port
,
p0
|
0x0b
,
p1
|
0xb0
,
ev
->
data
.
control
.
param
&
0x7f
,
ev
->
data
.
control
.
value
&
0x7f
);
break
;
case
SNDRV_SEQ_EVENT_PGMCHANGE
:
output_packet
(
port
,
p0
|
0x0c
,
p1
|
0xc0
,
ev
->
data
.
control
.
value
&
0x7f
,
0
);
break
;
case
SNDRV_SEQ_EVENT_CHANPRESS
:
output_packet
(
port
,
p0
|
0x0d
,
p1
|
0xd0
,
ev
->
data
.
control
.
value
&
0x7f
,
0
);
break
;
case
SNDRV_SEQ_EVENT_PITCHBEND
:
output_packet
(
port
,
p0
|
0x0e
,
p1
|
0xe0
,
(
ev
->
data
.
control
.
value
+
0x2000
)
&
0x7f
,
((
ev
->
data
.
control
.
value
+
0x2000
)
>>
7
)
&
0x7f
);
break
;
case
SNDRV_SEQ_EVENT_CONTROL14
:
if
(
ev
->
data
.
control
.
param
<
0x20
)
{
output_packet
(
port
,
p0
|
0x0b
,
p1
|
0xb0
,
ev
->
data
.
control
.
param
,
(
ev
->
data
.
control
.
value
>>
7
)
&
0x7f
);
output_packet
(
port
,
p0
|
0x0b
,
p1
|
0xb0
,
ev
->
data
.
control
.
param
+
0x20
,
ev
->
data
.
control
.
value
&
0x7f
);
}
else
{
output_packet
(
port
,
p0
|
0x0b
,
p1
|
0xb0
,
ev
->
data
.
control
.
param
&
0x7f
,
ev
->
data
.
control
.
value
&
0x7f
);
}
break
;
case
SNDRV_SEQ_EVENT_SONGPOS
:
output_packet
(
port
,
p0
|
0x03
,
0xf2
,
ev
->
data
.
control
.
value
&
0x7f
,
(
ev
->
data
.
control
.
value
>>
7
)
&
0x7f
);
break
;
case
SNDRV_SEQ_EVENT_SONGSEL
:
output_packet
(
port
,
p0
|
0x02
,
0xf3
,
ev
->
data
.
control
.
value
&
0x7f
,
0
);
break
;
case
SNDRV_SEQ_EVENT_QFRAME
:
output_packet
(
port
,
p0
|
0x02
,
0xf1
,
ev
->
data
.
control
.
value
&
0x7f
,
0
);
break
;
case
SNDRV_SEQ_EVENT_START
:
output_packet
(
port
,
p0
|
0x0f
,
0xfa
,
0
,
0
);
break
;
case
SNDRV_SEQ_EVENT_CONTINUE
:
output_packet
(
port
,
p0
|
0x0f
,
0xfb
,
0
,
0
);
break
;
case
SNDRV_SEQ_EVENT_STOP
:
output_packet
(
port
,
p0
|
0x0f
,
0xfc
,
0
,
0
);
break
;
case
SNDRV_SEQ_EVENT_CLOCK
:
output_packet
(
port
,
p0
|
0x0f
,
0xf8
,
0
,
0
);
break
;
case
SNDRV_SEQ_EVENT_TUNE_REQUEST
:
output_packet
(
port
,
p0
|
0x05
,
0xf6
,
0
,
0
);
break
;
case
SNDRV_SEQ_EVENT_RESET
:
output_packet
(
port
,
p0
|
0x0f
,
0xff
,
0
,
0
);
break
;
case
SNDRV_SEQ_EVENT_SENSING
:
output_packet
(
port
,
p0
|
0x0f
,
0xfe
,
0
,
0
);
break
;
case
SNDRV_SEQ_EVENT_SYSEX
:
err
=
snd_seq_dump_var_event
(
ev
,
snd_usbmidi_sysex_dump
,
port
);
if
(
err
<
0
)
return
err
;
break
;
default:
return
0
;
}
tasklet_hi_schedule
(
&
port
->
ep
->
tasklet
);
usbmidi_out_port_t
*
port
=
(
usbmidi_out_port_t
*
)
substream
->
runtime
->
private_data
;
port
->
active
=
up
;
if
(
up
)
tasklet_hi_schedule
(
&
port
->
ep
->
tasklet
);
}
static
int
snd_usbmidi_input_open
(
snd_rawmidi_substream_t
*
substream
)
{
snd_usb_midi_t
*
umidi
=
snd_magic_cast
(
snd_usb_midi_t
,
substream
->
rmidi
->
private_data
,
return
-
ENXIO
);
usbmidi_in_port_t
*
port
=
NULL
;
int
i
,
j
;
for
(
i
=
0
;
i
<
MIDI_MAX_ENDPOINTS
;
++
i
)
if
(
umidi
->
endpoints
[
i
].
in
)
for
(
j
=
0
;
j
<
0x10
;
++
j
)
if
(
umidi
->
endpoints
[
i
].
in
->
ports
[
j
].
substream
==
substream
)
{
port
=
&
umidi
->
endpoints
[
i
].
in
->
ports
[
j
];
break
;
}
if
(
!
port
)
return
-
ENXIO
;
substream
->
runtime
->
private_data
=
port
;
return
0
;
}
static
int
snd_usbmidi_input_close
(
snd_rawmidi_substream_t
*
substream
)
{
return
0
;
}
static
void
snd_usbmidi_input_trigger
(
snd_rawmidi_substream_t
*
substream
,
int
up
)
{
usbmidi_in_port_t
*
port
=
(
usbmidi_in_port_t
*
)
substream
->
runtime
->
private_data
;
port
->
active
=
up
;
}
static
snd_rawmidi_ops_t
snd_usbmidi_output_ops
=
{
.
open
=
snd_usbmidi_output_open
,
.
close
=
snd_usbmidi_output_close
,
.
trigger
=
snd_usbmidi_output_trigger
,
};
static
snd_rawmidi_ops_t
snd_usbmidi_input_ops
=
{
.
open
=
snd_usbmidi_input_open
,
.
close
=
snd_usbmidi_input_close
,
.
trigger
=
snd_usbmidi_input_trigger
};
/*
* Frees an input endpoint.
* May be called when ep hasn't been initialized completely.
*/
static
void
snd_usbmidi_in_endpoint_delete
(
snd_usb_midi_in_endpoint_t
*
ep
)
{
int
i
;
if
(
ep
->
urb
)
{
if
(
ep
->
urb
->
transfer_buffer
)
{
usb_unlink_urb
(
ep
->
urb
);
...
...
@@ -530,9 +507,6 @@ static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
}
usb_free_urb
(
ep
->
urb
);
}
for
(
i
=
0
;
i
<
0x10
;
++
i
)
if
(
ep
->
ports
[
i
].
midi_event
)
snd_midi_event_free
(
ep
->
ports
[
i
].
midi_event
);
snd_magic_kfree
(
ep
);
}
...
...
@@ -540,11 +514,10 @@ static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
* For Roland devices, use the alternate setting which uses interrupt
* transfers for input.
*/
static
usb_endpoint_descriptor_t
*
snd_usbmidi_get_int_epd
(
snd_usb_midi_t
*
umidi
,
uint8_t
epnum
)
static
struct
usb_endpoint_descriptor
*
snd_usbmidi_get_int_epd
(
snd_usb_midi_t
*
umidi
)
{
usb_interface_t
*
intf
;
usb_interface_descriptor_t
*
intfd
;
struct
usb_interface
*
intf
;
struct
usb_interface_descriptor
*
intfd
;
if
(
umidi
->
chip
->
dev
->
descriptor
.
idVendor
!=
0x0582
)
return
NULL
;
...
...
@@ -569,41 +542,37 @@ 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
)
static
struct
usb_endpoint_descriptor
*
snd_usbmidi_get_midiman_int_epd
(
snd_usb_midi_t
*
umidi
)
{
usb_interface_t
*
intf
=
umidi
->
iface
;
if
(
!
intf
)
struct
usb_interface
*
intf
=
umidi
->
iface
;
if
(
!
intf
||
intf
->
altsetting
[
0
].
bNumEndpoints
<
1
)
return
NULL
;
return
&
intf
->
altsetting
[
0
].
endpoint
[
0
];
}
/*
* Creates an input endpoint, and initalizes input ports.
* ALSA ports are created later.
* Creates an input endpoint.
*/
static
int
snd_usbmidi_in_endpoint_create
(
snd_usb_midi_t
*
umidi
,
snd_usb_midi_endpoint_info_t
*
ep_info
,
snd_usb_midi_endpoint_t
*
rep
)
{
snd_usb_midi_in_endpoint_t
*
ep
;
usb_endpoint_descriptor_t
*
int_epd
;
struct
usb_endpoint_descriptor
*
int_epd
;
void
*
buffer
;
unsigned
int
pipe
;
int
length
,
i
,
err
;
int
length
;
rep
->
in
=
NULL
;
ep
=
snd_magic_kcalloc
(
snd_usb_midi_in_endpoint_t
,
0
,
GFP_KERNEL
);
if
(
!
ep
)
return
-
ENOMEM
;
ep
->
umidi
=
umidi
;
ep
->
ep
=
rep
;
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
);
int_epd
=
snd_usbmidi_get_int_epd
(
umidi
);
ep
->
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
ep
->
urb
)
{
...
...
@@ -627,16 +596,6 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
FILL_BULK_URB
(
ep
->
urb
,
umidi
->
chip
->
dev
,
pipe
,
buffer
,
length
,
snd_usbmidi_in_urb_complete
,
ep
);
for
(
i
=
0
;
i
<
0x10
;
++
i
)
if
(
ep_info
->
in_cables
&
(
1
<<
i
))
{
err
=
snd_midi_event_new
(
INPUT_BUFFER_SIZE
,
&
ep
->
ports
[
i
].
midi_event
);
if
(
err
<
0
)
{
snd_usbmidi_in_endpoint_delete
(
ep
);
return
-
ENOMEM
;
}
}
rep
->
in
=
ep
;
return
0
;
}
...
...
@@ -670,7 +629,6 @@ static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
/*
* Creates an output endpoint, and initializes output ports.
* ALSA ports are created later.
*/
static
int
snd_usbmidi_out_endpoint_create
(
snd_usb_midi_t
*
umidi
,
snd_usb_midi_endpoint_info_t
*
ep_info
,
...
...
@@ -716,143 +674,54 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
}
/*
* Frees
the sequencer client, endpoints and ports
.
* Frees
everything
.
*/
static
int
snd_usbmidi_seq_device_delete
(
snd_seq_device_t
*
seq_device
)
static
void
snd_usbmidi_free
(
snd_usb_midi_t
*
umidi
)
{
snd_usb_midi_t
*
umidi
;
int
i
,
j
;
umidi
=
(
snd_usb_midi_t
*
)
SNDRV_SEQ_DEVICE_ARGPTR
(
seq_device
);
int
i
;
if
(
umidi
->
seq_client
>=
0
)
{
snd_seq_delete_kernel_client
(
umidi
->
seq_client
);
umidi
->
seq_client
=
-
1
;
}
for
(
i
=
0
;
i
<
MIDI_MAX_ENDPOINTS
;
++
i
)
{
snd_usb_midi_endpoint_t
*
ep
=
&
umidi
->
endpoints
[
i
];
if
(
ep
->
out
)
{
if
(
ep
->
out
)
snd_usbmidi_out_endpoint_delete
(
ep
->
out
);
ep
->
out
=
NULL
;
}
if
(
ep
->
in
)
{
if
(
ep
->
in
)
snd_usbmidi_in_endpoint_delete
(
ep
->
in
);
ep
->
in
=
NULL
;
}
for
(
j
=
0
;
j
<
0x10
;
++
j
)
if
(
ep
->
rmidi
[
j
])
{
snd_device_free
(
umidi
->
chip
->
card
,
ep
->
rmidi
[
j
]);
ep
->
rmidi
[
j
]
=
NULL
;
}
}
return
0
;
snd_magic_kfree
(
umidi
)
;
}
/*
* Creates a sequencer port for an input/output cable pair.
*/
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
)
static
void
snd_usbmidi_rawmidi_free
(
snd_rawmidi_t
*
rmidi
)
{
int
cap
,
type
,
port
;
snd_seq_port_callback_t
port_callback
;
char
port_name
[
48
];
cap
=
0
;
memset
(
&
port_callback
,
0
,
sizeof
(
port_callback
));
port_callback
.
owner
=
THIS_MODULE
;
if
(
out_ep
)
{
port_callback
.
event_input
=
snd_usbmidi_event_input
;
port_callback
.
private_data
=
&
out_ep
->
ports
[
cable
];
cap
|=
SNDRV_SEQ_PORT_CAP_WRITE
|
SNDRV_SEQ_PORT_CAP_SUBS_WRITE
;
}
if
(
in_ep
)
{
cap
|=
SNDRV_SEQ_PORT_CAP_READ
|
SNDRV_SEQ_PORT_CAP_SUBS_READ
;
}
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
,
cap
,
type
,
port_name
);
if
(
port
<
0
)
{
snd_printk
(
KERN_ERR
"cannot create port (error code %d)
\n
"
,
port
);
return
port
;
}
if
(
in_ep
)
in_ep
->
ports
[
cable
].
seq_port
=
port
;
return
port
;
snd_usb_midi_t
*
umidi
=
snd_magic_cast
(
snd_usb_midi_t
,
rmidi
->
private_data
,
return
);
snd_usbmidi_free
(
umidi
);
}
/*
* 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
)
static
snd_rawmidi_substream_t
*
snd_usbmidi_find_substream
(
snd_usb_midi_t
*
umidi
,
int
stream
,
int
number
)
{
snd_rawmidi_t
*
rmidi
;
snd_virmidi_dev_t
*
rdev
;
int
err
;
struct
list_head
*
list
;
*
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
);
rdev
->
seq_mode
=
SNDRV_VIRMIDI_SEQ_ATTACH
;
rdev
->
client
=
umidi
->
seq_client
;
rdev
->
port
=
port
;
err
=
snd_device_register
(
umidi
->
chip
->
card
,
rmidi
);
if
(
err
<
0
)
{
snd_device_free
(
umidi
->
chip
->
card
,
rmidi
);
return
err
;
list_for_each
(
list
,
&
umidi
->
rmidi
->
streams
[
stream
].
substreams
)
{
snd_rawmidi_substream_t
*
substream
=
list_entry
(
list
,
snd_rawmidi_substream_t
,
list
);
if
(
substream
->
number
==
number
)
return
substream
;
}
*
rrmidi
=
rmidi
;
return
0
;
return
NULL
;
}
/*
* 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
)
static
void
snd_usbmidi_init_substream
(
snd_usb_midi_t
*
umidi
,
int
stream
,
int
number
,
snd_rawmidi_substream_t
**
rsubstream
)
{
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
;
snd_rawmidi_substream_t
*
substream
=
snd_usbmidi_find_substream
(
umidi
,
stream
,
number
);
if
(
!
substream
)
{
snd_printd
(
KERN_ERR
"substream %d:%d not found
\n
"
,
stream
,
number
);
return
;
}
return
0
;
/* TODO: read port name from jack descriptor */
snprintf
(
substream
->
name
,
sizeof
(
substream
->
name
),
"%s Port %d"
,
umidi
->
chip
->
card
->
shortname
,
number
);
*
rsubstream
=
substream
;
}
/*
...
...
@@ -861,7 +730,8 @@ static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi,
static
int
snd_usbmidi_create_endpoints
(
snd_usb_midi_t
*
umidi
,
snd_usb_midi_endpoint_info_t
*
endpoints
)
{
int
i
,
err
,
port_idx
=
0
;
int
i
,
j
,
err
;
int
out_ports
=
0
,
in_ports
=
0
;
for
(
i
=
0
;
i
<
MIDI_MAX_ENDPOINTS
;
++
i
)
{
if
(
!
endpoints
[
i
].
epnum
)
...
...
@@ -878,15 +748,22 @@ static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
if
(
err
<
0
)
return
err
;
}
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
"
,
endpoints
[
i
].
epnum
,
snd_usbmidi_count_bits
(
endpoints
[
i
].
out_cables
),
snd_usbmidi_count_bits
(
endpoints
[
i
].
in_cables
));
for
(
j
=
0
;
j
<
0x10
;
++
j
)
{
if
(
endpoints
[
i
].
out_cables
&
(
1
<<
j
))
{
snd_usbmidi_init_substream
(
umidi
,
SNDRV_RAWMIDI_STREAM_OUTPUT
,
out_ports
,
&
umidi
->
endpoints
[
i
].
out
->
ports
[
j
].
substream
);
++
out_ports
;
}
if
(
endpoints
[
i
].
in_cables
&
(
1
<<
j
))
{
snd_usbmidi_init_substream
(
umidi
,
SNDRV_RAWMIDI_STREAM_INPUT
,
in_ports
,
&
umidi
->
endpoints
[
i
].
in
->
ports
[
j
].
substream
);
++
in_ports
;
}
}
}
printk
(
KERN_INFO
"snd-usb-midi: created %d output and %d input ports
\n
"
,
out_ports
,
in_ports
);
return
0
;
}
...
...
@@ -896,18 +773,18 @@ static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
static
int
snd_usbmidi_get_ms_info
(
snd_usb_midi_t
*
umidi
,
snd_usb_midi_endpoint_info_t
*
endpoints
)
{
usb_interface_t
*
intf
;
usb_interface_descriptor_t
*
intfd
;
usb_ms_header_descriptor_t
*
ms_header
;
usb_endpoint_descriptor_t
*
ep
;
usb_ms_endpoint_descriptor_t
*
ms_ep
;
struct
usb_interface
*
intf
;
struct
usb_interface_descriptor
*
intfd
;
struct
usb_ms_header_descriptor
*
ms_header
;
struct
usb_endpoint_descriptor
*
ep
;
struct
usb_ms_endpoint_descriptor
*
ms_ep
;
int
i
,
epidx
;
intf
=
umidi
->
iface
;
if
(
!
intf
)
return
-
ENXIO
;
intfd
=
&
intf
->
altsetting
[
0
];
ms_header
=
(
usb_ms_header_descriptor_t
*
)
intfd
->
extra
;
ms_header
=
(
struct
usb_ms_header_descriptor
*
)
intfd
->
extra
;
if
(
intfd
->
extralen
>=
7
&&
ms_header
->
bLength
>=
7
&&
ms_header
->
bDescriptorType
==
USB_DT_CS_INTERFACE
&&
...
...
@@ -922,7 +799,7 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
ep
=
&
intfd
->
endpoint
[
i
];
if
((
ep
->
bmAttributes
&
USB_ENDPOINT_XFERTYPE_MASK
)
!=
USB_ENDPOINT_XFER_BULK
)
continue
;
ms_ep
=
(
usb_ms_endpoint_descriptor_t
*
)
ep
->
extra
;
ms_ep
=
(
struct
usb_ms_endpoint_descriptor
*
)
ep
->
extra
;
if
(
ep
->
extralen
<
4
||
ms_ep
->
bLength
<
4
||
ms_ep
->
bDescriptorType
!=
USB_DT_CS_ENDPOINT
||
...
...
@@ -957,9 +834,9 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
static
int
snd_usbmidi_detect_endpoint
(
snd_usb_midi_t
*
umidi
,
snd_usb_midi_endpoint_info_t
*
endpoint
)
{
usb_interface_t
*
intf
;
usb_interface_descriptor_t
*
intfd
;
usb_endpoint_descriptor_t
*
epd
;
struct
usb_interface
*
intf
;
struct
usb_interface_descriptor
*
intfd
;
struct
usb_endpoint_descriptor
*
epd
;
if
(
endpoint
->
epnum
==
-
1
)
{
intf
=
umidi
->
iface
;
...
...
@@ -980,8 +857,8 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
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
;
struct
usb_interface
*
intf
;
struct
usb_interface_descriptor
*
intfd
;
uint8_t
*
cs_desc
;
intf
=
umidi
->
iface
;
...
...
@@ -1014,9 +891,9 @@ static int snd_usbmidi_detect_yamaha(snd_usb_midi_t* umidi,
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
;
struct
usb_interface
*
intf
;
struct
usb_interface_descriptor
*
intfd
;
struct
usb_endpoint_descriptor
*
epd
;
int
cable
,
err
;
intf
=
umidi
->
iface
;
...
...
@@ -1071,77 +948,65 @@ static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports
}
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
;
}
snd_usbmidi_init_substream
(
umidi
,
SNDRV_RAWMIDI_STREAM_OUTPUT
,
cable
,
&
umidi
->
endpoints
[
cable
&
1
].
out
->
ports
[
cable
].
substream
);
snd_usbmidi_init_substream
(
umidi
,
SNDRV_RAWMIDI_STREAM_INPUT
,
cable
,
&
umidi
->
endpoints
[
0
].
in
->
ports
[
cable
].
substream
);
}
return
0
;
}
static
int
snd_usbmidi_create_rawmidi
(
snd_usb_midi_t
*
umidi
,
int
out_ports
,
int
in_ports
)
{
snd_rawmidi_t
*
rmidi
;
int
err
;
err
=
snd_rawmidi_new
(
umidi
->
chip
->
card
,
"USB MIDI"
,
umidi
->
chip
->
next_midi_device
++
,
out_ports
,
in_ports
,
&
rmidi
);
if
(
err
<
0
)
return
err
;
strcpy
(
rmidi
->
name
,
umidi
->
chip
->
card
->
longname
);
rmidi
->
info_flags
=
SNDRV_RAWMIDI_INFO_OUTPUT
|
SNDRV_RAWMIDI_INFO_INPUT
|
SNDRV_RAWMIDI_INFO_DUPLEX
;
rmidi
->
private_data
=
umidi
;
rmidi
->
private_free
=
snd_usbmidi_rawmidi_free
;
snd_rawmidi_set_ops
(
rmidi
,
SNDRV_RAWMIDI_STREAM_OUTPUT
,
&
snd_usbmidi_output_ops
);
snd_rawmidi_set_ops
(
rmidi
,
SNDRV_RAWMIDI_STREAM_INPUT
,
&
snd_usbmidi_input_ops
);
umidi
->
rmidi
=
rmidi
;
return
0
;
}
/*
*
Initialize the sequencer devi
ce.
*
Creates and registers everything needed for a MIDI streaming interfa
ce.
*/
static
int
snd_usbmidi_seq_device_new
(
snd_seq_device_t
*
seq_device
)
int
snd_usb_create_midi_interface
(
snd_usb_audio_t
*
chip
,
struct
usb_interface
*
iface
,
const
snd_usb_audio_quirk_t
*
quirk
)
{
snd_usb_midi_t
*
umidi
;
usb_device_t
*
dev
;
snd_seq_client_callback_t
client_callback
;
snd_seq_client_info_t
client_info
;
snd_usb_midi_endpoint_info_t
endpoints
[
MIDI_MAX_ENDPOINTS
];
int
out_ports
,
in_ports
;
int
i
,
err
;
umidi
=
(
snd_usb_midi_t
*
)
SNDRV_SEQ_DEVICE_ARGPTR
(
seq_device
);
memset
(
&
client_callback
,
0
,
sizeof
(
client_callback
));
client_callback
.
allow_output
=
1
;
client_callback
.
allow_input
=
1
;
umidi
->
seq_client
=
snd_seq_create_kernel_client
(
umidi
->
chip
->
card
,
0
,
&
client_callback
);
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
;
dev
=
umidi
->
chip
->
dev
;
if
(
dev
->
descriptor
.
iProduct
)
err
=
usb_string
(
dev
,
dev
->
descriptor
.
iProduct
,
client_info
.
name
,
sizeof
(
client_info
.
name
));
else
err
=
0
;
if
(
err
<=
0
)
{
if
(
umidi
->
quirk
&&
umidi
->
quirk
->
product_name
)
{
strncpy
(
client_info
.
name
,
umidi
->
quirk
->
product_name
,
sizeof
(
client_info
.
name
)
-
1
);
client_info
.
name
[
sizeof
(
client_info
.
name
)
-
1
]
=
'\0'
;
}
else
{
sprintf
(
client_info
.
name
,
"USB Device %#04x:%#04x"
,
dev
->
descriptor
.
idVendor
,
dev
->
descriptor
.
idProduct
);
}
}
snd_seq_kernel_client_ctl
(
umidi
->
seq_client
,
SNDRV_SEQ_IOCTL_SET_CLIENT_INFO
,
&
client_info
);
umidi
=
snd_magic_kcalloc
(
snd_usb_midi_t
,
0
,
GFP_KERNEL
);
if
(
!
umidi
)
return
-
ENOMEM
;
umidi
->
chip
=
chip
;
umidi
->
iface
=
iface
;
umidi
->
quirk
=
quirk
;
/* detect the endpoint(s) to use */
memset
(
endpoints
,
0
,
sizeof
(
endpoints
));
if
(
!
umidi
->
quirk
)
{
if
(
!
quirk
)
{
err
=
snd_usbmidi_get_ms_info
(
umidi
,
endpoints
);
}
else
{
switch
(
umidi
->
quirk
->
type
)
{
switch
(
quirk
->
type
)
{
case
QUIRK_MIDI_FIXED_ENDPOINT
:
memcpy
(
&
endpoints
[
0
],
umidi
->
quirk
->
data
,
memcpy
(
&
endpoints
[
0
],
quirk
->
data
,
sizeof
(
snd_usb_midi_endpoint_info_t
));
err
=
snd_usbmidi_detect_endpoint
(
umidi
,
&
endpoints
[
0
]);
break
;
...
...
@@ -1152,21 +1017,40 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
err
=
0
;
break
;
default:
snd_printd
(
KERN_ERR
"invalid quirk type %d
\n
"
,
umidi
->
quirk
->
type
);
snd_printd
(
KERN_ERR
"invalid quirk type %d
\n
"
,
quirk
->
type
);
err
=
-
ENXIO
;
break
;
}
}
if
(
err
<
0
)
{
snd_magic_kfree
(
umidi
);
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
);
/* create rawmidi device */
if
(
quirk
&&
quirk
->
type
==
QUIRK_MIDI_MIDIMAN
)
{
in_ports
=
out_ports
=
(
int
)
quirk
->
data
;
}
else
{
out_ports
=
0
;
in_ports
=
0
;
for
(
i
=
0
;
i
<
MIDI_MAX_ENDPOINTS
;
++
i
)
{
out_ports
+=
snd_usbmidi_count_bits
(
endpoints
[
i
].
out_cables
);
in_ports
+=
snd_usbmidi_count_bits
(
endpoints
[
i
].
in_cables
);
}
}
err
=
snd_usbmidi_create_rawmidi
(
umidi
,
out_ports
,
in_ports
);
if
(
err
<
0
)
{
snd_usbmidi_seq_device_delete
(
seq_device
);
snd_magic_kfree
(
umidi
);
return
err
;
}
/* create endpoint/port structures */
if
(
quirk
&&
quirk
->
type
==
QUIRK_MIDI_MIDIMAN
)
err
=
snd_usbmidi_create_endpoints_midiman
(
umidi
,
(
int
)
quirk
->
data
);
else
err
=
snd_usbmidi_create_endpoints
(
umidi
,
endpoints
);
if
(
err
<
0
)
{
snd_usbmidi_free
(
umidi
);
return
err
;
}
...
...
@@ -1176,22 +1060,3 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
GFP_KERNEL
);
return
0
;
}
static
int
__init
snd_usbmidi_module_init
(
void
)
{
static
snd_seq_dev_ops_t
ops
=
{
snd_usbmidi_seq_device_new
,
snd_usbmidi_seq_device_delete
};
return
snd_seq_device_register_driver
(
SNDRV_SEQ_DEV_ID_USBMIDI
,
&
ops
,
sizeof
(
snd_usb_midi_t
));
}
static
void
__exit
snd_usbmidi_module_exit
(
void
)
{
snd_seq_device_unregister_driver
(
SNDRV_SEQ_DEV_ID_USBMIDI
);
}
module_init
(
snd_usbmidi_module_init
)
module_exit
(
snd_usbmidi_module_exit
)
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