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
Kirill Smelkov
linux
Commits
156366d3
Commit
156366d3
authored
Mar 02, 2010
by
Takashi Iwai
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote branch 'alsa/devel' into topic/misc
Conflicts: sound/usb/usbaudio.c
parents
7f9320d4
0a566ec2
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
38 additions
and
156 deletions
+38
-156
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/ALSA-Configuration.txt
+1
-1
sound/usb/Kconfig
sound/usb/Kconfig
+3
-3
sound/usb/ua101.c
sound/usb/ua101.c
+33
-67
sound/usb/usbaudio.c
sound/usb/usbaudio.c
+0
-53
sound/usb/usbaudio.h
sound/usb/usbaudio.h
+1
-2
sound/usb/usbquirks.h
sound/usb/usbquirks.h
+0
-30
No files found.
Documentation/sound/alsa/ALSA-Configuration.txt
View file @
156366d3
...
@@ -1812,7 +1812,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
...
@@ -1812,7 +1812,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module snd-ua101
Module snd-ua101
----------------
----------------
Module for the Edirol UA-101
audio/MIDI interface
.
Module for the Edirol UA-101
/UA-1000 audio/MIDI interfaces
.
This module supports multiple devices, autoprobe and hotplugging.
This module supports multiple devices, autoprobe and hotplugging.
...
...
sound/usb/Kconfig
View file @
156366d3
...
@@ -22,13 +22,13 @@ config SND_USB_AUDIO
...
@@ -22,13 +22,13 @@ config SND_USB_AUDIO
will be called snd-usb-audio.
will be called snd-usb-audio.
config SND_USB_UA101
config SND_USB_UA101
tristate "Edirol UA-101 driver (EXPERIMENTAL)"
tristate "Edirol UA-101
/UA-1000
driver (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on EXPERIMENTAL
select SND_PCM
select SND_PCM
select SND_RAWMIDI
select SND_RAWMIDI
help
help
Say Y here to include support for the Edirol UA-101 a
udio/MIDI
Say Y here to include support for the Edirol UA-101 a
nd UA-1000
interface
.
audio/MIDI interfaces
.
To compile this driver as a module, choose M here: the module
To compile this driver as a module, choose M here: the module
will be called snd-ua101.
will be called snd-ua101.
...
...
sound/usb/ua101.c
View file @
156366d3
/*
/*
* Edirol UA-101 driver
* Edirol UA-101
/UA-1000
driver
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
*
*
* This driver is free software: you can redistribute it and/or modify
* This driver is free software: you can redistribute it and/or modify
...
@@ -25,13 +25,10 @@
...
@@ -25,13 +25,10 @@
#include <sound/pcm_params.h>
#include <sound/pcm_params.h>
#include "usbaudio.h"
#include "usbaudio.h"
MODULE_DESCRIPTION
(
"Edirol UA-101 driver"
);
MODULE_DESCRIPTION
(
"Edirol UA-101
/1000
driver"
);
MODULE_AUTHOR
(
"Clemens Ladisch <clemens@ladisch.de>"
);
MODULE_AUTHOR
(
"Clemens Ladisch <clemens@ladisch.de>"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_SUPPORTED_DEVICE
(
"{{Edirol,UA-101}}"
);
MODULE_SUPPORTED_DEVICE
(
"{{Edirol,UA-101},{Edirol,UA-1000}}"
);
/* I use my UA-1A for testing because I don't have a UA-101 ... */
#define UA1A_HACK
/*
/*
* Should not be lower than the minimum scheduling delay of the host
* Should not be lower than the minimum scheduling delay of the host
...
@@ -132,9 +129,6 @@ struct ua101 {
...
@@ -132,9 +129,6 @@ struct ua101 {
dma_addr_t
dma
;
dma_addr_t
dma
;
}
buffers
[
MAX_MEMORY_BUFFERS
];
}
buffers
[
MAX_MEMORY_BUFFERS
];
}
capture
,
playback
;
}
capture
,
playback
;
unsigned
int
fps
[
10
];
unsigned
int
frame_counter
;
};
};
static
DEFINE_MUTEX
(
devices_mutex
);
static
DEFINE_MUTEX
(
devices_mutex
);
...
@@ -424,16 +418,6 @@ static void capture_urb_complete(struct urb *urb)
...
@@ -424,16 +418,6 @@ static void capture_urb_complete(struct urb *urb)
if
(
do_period_elapsed
)
if
(
do_period_elapsed
)
snd_pcm_period_elapsed
(
stream
->
substream
);
snd_pcm_period_elapsed
(
stream
->
substream
);
/* for debugging: measure the sample rate relative to the USB clock */
ua
->
fps
[
ua
->
frame_counter
++
/
ua
->
packets_per_second
]
+=
frames
;
if
(
ua
->
frame_counter
>=
ARRAY_SIZE
(
ua
->
fps
)
*
ua
->
packets_per_second
)
{
printk
(
KERN_DEBUG
"capture rate:"
);
for
(
frames
=
0
;
frames
<
ARRAY_SIZE
(
ua
->
fps
);
++
frames
)
printk
(
KERN_CONT
" %u"
,
ua
->
fps
[
frames
]);
printk
(
KERN_CONT
"
\n
"
);
memset
(
ua
->
fps
,
0
,
sizeof
(
ua
->
fps
));
ua
->
frame_counter
=
0
;
}
return
;
return
;
stream_stopped:
stream_stopped:
...
@@ -1200,13 +1184,30 @@ static int ua101_probe(struct usb_interface *interface,
...
@@ -1200,13 +1184,30 @@ static int ua101_probe(struct usb_interface *interface,
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
midi_ep
.
data
=
&
midi_ep
};
};
static
const
int
intf_numbers
[
2
][
3
]
=
{
{
/* UA-101 */
[
INTF_PLAYBACK
]
=
0
,
[
INTF_CAPTURE
]
=
1
,
[
INTF_MIDI
]
=
2
,
},
{
/* UA-1000 */
[
INTF_CAPTURE
]
=
1
,
[
INTF_PLAYBACK
]
=
2
,
[
INTF_MIDI
]
=
3
,
},
};
struct
snd_card
*
card
;
struct
snd_card
*
card
;
struct
ua101
*
ua
;
struct
ua101
*
ua
;
unsigned
int
card_index
,
i
;
unsigned
int
card_index
,
i
;
int
is_ua1000
;
const
char
*
name
;
char
usb_path
[
32
];
char
usb_path
[
32
];
int
err
;
int
err
;
if
(
interface
->
altsetting
->
desc
.
bInterfaceNumber
!=
0
)
is_ua1000
=
usb_id
->
idProduct
==
0x0044
;
if
(
interface
->
altsetting
->
desc
.
bInterfaceNumber
!=
intf_numbers
[
is_ua1000
][
0
])
return
-
ENODEV
;
return
-
ENODEV
;
mutex_lock
(
&
devices_mutex
);
mutex_lock
(
&
devices_mutex
);
...
@@ -1239,20 +1240,13 @@ static int ua101_probe(struct usb_interface *interface,
...
@@ -1239,20 +1240,13 @@ static int ua101_probe(struct usb_interface *interface,
init_waitqueue_head
(
&
ua
->
rate_feedback_wait
);
init_waitqueue_head
(
&
ua
->
rate_feedback_wait
);
init_waitqueue_head
(
&
ua
->
alsa_playback_wait
);
init_waitqueue_head
(
&
ua
->
alsa_playback_wait
);
#ifdef UA1A_HACK
if
(
ua
->
dev
->
descriptor
.
idProduct
==
cpu_to_le16
(
0x0018
))
{
ua
->
intf
[
2
]
=
interface
;
ua
->
intf
[
0
]
=
usb_ifnum_to_if
(
ua
->
dev
,
1
);
ua
->
intf
[
1
]
=
usb_ifnum_to_if
(
ua
->
dev
,
2
);
usb_driver_claim_interface
(
&
ua101_driver
,
ua
->
intf
[
0
],
ua
);
usb_driver_claim_interface
(
&
ua101_driver
,
ua
->
intf
[
1
],
ua
);
}
else
{
#endif
ua
->
intf
[
0
]
=
interface
;
ua
->
intf
[
0
]
=
interface
;
for
(
i
=
1
;
i
<
ARRAY_SIZE
(
ua
->
intf
);
++
i
)
{
for
(
i
=
1
;
i
<
ARRAY_SIZE
(
ua
->
intf
);
++
i
)
{
ua
->
intf
[
i
]
=
usb_ifnum_to_if
(
ua
->
dev
,
i
);
ua
->
intf
[
i
]
=
usb_ifnum_to_if
(
ua
->
dev
,
intf_numbers
[
is_ua1000
][
i
]);
if
(
!
ua
->
intf
[
i
])
{
if
(
!
ua
->
intf
[
i
])
{
dev_err
(
&
ua
->
dev
->
dev
,
"interface %u not found
\n
"
,
i
);
dev_err
(
&
ua
->
dev
->
dev
,
"interface %u not found
\n
"
,
intf_numbers
[
is_ua1000
][
i
]);
err
=
-
ENXIO
;
err
=
-
ENXIO
;
goto
probe_error
;
goto
probe_error
;
}
}
...
@@ -1264,39 +1258,19 @@ static int ua101_probe(struct usb_interface *interface,
...
@@ -1264,39 +1258,19 @@ static int ua101_probe(struct usb_interface *interface,
goto
probe_error
;
goto
probe_error
;
}
}
}
}
#ifdef UA1A_HACK
}
#endif
snd_card_set_dev
(
card
,
&
interface
->
dev
);
snd_card_set_dev
(
card
,
&
interface
->
dev
);
#ifdef UA1A_HACK
if
(
ua
->
dev
->
descriptor
.
idProduct
==
cpu_to_le16
(
0x0018
))
{
ua
->
format_bit
=
SNDRV_PCM_FMTBIT_S16_LE
;
ua
->
rate
=
44100
;
ua
->
packets_per_second
=
1000
;
ua
->
capture
.
channels
=
2
;
ua
->
playback
.
channels
=
2
;
ua
->
capture
.
frame_bytes
=
4
;
ua
->
playback
.
frame_bytes
=
4
;
ua
->
capture
.
usb_pipe
=
usb_rcvisocpipe
(
ua
->
dev
,
2
);
ua
->
playback
.
usb_pipe
=
usb_sndisocpipe
(
ua
->
dev
,
1
);
ua
->
capture
.
max_packet_bytes
=
192
;
ua
->
playback
.
max_packet_bytes
=
192
;
}
else
{
#endif
err
=
detect_usb_format
(
ua
);
err
=
detect_usb_format
(
ua
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
probe_error
;
goto
probe_error
;
#ifdef UA1A_HACK
}
#endif
name
=
usb_id
->
idProduct
==
0x0044
?
"UA-1000"
:
"UA-101"
;
strcpy
(
card
->
driver
,
"UA-101"
);
strcpy
(
card
->
driver
,
"UA-101"
);
strcpy
(
card
->
shortname
,
"UA-101"
);
strcpy
(
card
->
shortname
,
name
);
usb_make_path
(
ua
->
dev
,
usb_path
,
sizeof
(
usb_path
));
usb_make_path
(
ua
->
dev
,
usb_path
,
sizeof
(
usb_path
));
snprintf
(
ua
->
card
->
longname
,
sizeof
(
ua
->
card
->
longname
),
snprintf
(
ua
->
card
->
longname
,
sizeof
(
ua
->
card
->
longname
),
"EDIROL
UA-101 (serial %s), %u Hz at %s, %s speed"
,
"EDIROL
%s (serial %s), %u Hz at %s, %s speed"
,
name
,
ua
->
dev
->
serial
?
ua
->
dev
->
serial
:
"?"
,
ua
->
rate
,
usb_path
,
ua
->
dev
->
serial
?
ua
->
dev
->
serial
:
"?"
,
ua
->
rate
,
usb_path
,
ua
->
dev
->
speed
==
USB_SPEED_HIGH
?
"high"
:
"full"
);
ua
->
dev
->
speed
==
USB_SPEED_HIGH
?
"high"
:
"full"
);
...
@@ -1314,24 +1288,18 @@ static int ua101_probe(struct usb_interface *interface,
...
@@ -1314,24 +1288,18 @@ static int ua101_probe(struct usb_interface *interface,
if
(
err
<
0
)
if
(
err
<
0
)
goto
probe_error
;
goto
probe_error
;
err
=
snd_pcm_new
(
card
,
"UA-101"
,
0
,
1
,
1
,
&
ua
->
pcm
);
err
=
snd_pcm_new
(
card
,
name
,
0
,
1
,
1
,
&
ua
->
pcm
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
probe_error
;
goto
probe_error
;
ua
->
pcm
->
private_data
=
ua
;
ua
->
pcm
->
private_data
=
ua
;
strcpy
(
ua
->
pcm
->
name
,
"UA-101"
);
strcpy
(
ua
->
pcm
->
name
,
name
);
snd_pcm_set_ops
(
ua
->
pcm
,
SNDRV_PCM_STREAM_PLAYBACK
,
&
playback_pcm_ops
);
snd_pcm_set_ops
(
ua
->
pcm
,
SNDRV_PCM_STREAM_PLAYBACK
,
&
playback_pcm_ops
);
snd_pcm_set_ops
(
ua
->
pcm
,
SNDRV_PCM_STREAM_CAPTURE
,
&
capture_pcm_ops
);
snd_pcm_set_ops
(
ua
->
pcm
,
SNDRV_PCM_STREAM_CAPTURE
,
&
capture_pcm_ops
);
#ifdef UA1A_HACK
if
(
ua
->
dev
->
descriptor
.
idProduct
!=
cpu_to_le16
(
0x0018
))
{
#endif
err
=
snd_usbmidi_create
(
card
,
ua
->
intf
[
INTF_MIDI
],
err
=
snd_usbmidi_create
(
card
,
ua
->
intf
[
INTF_MIDI
],
&
ua
->
midi_list
,
&
midi_quirk
);
&
ua
->
midi_list
,
&
midi_quirk
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
probe_error
;
goto
probe_error
;
#ifdef UA1A_HACK
}
#endif
err
=
snd_card_register
(
card
);
err
=
snd_card_register
(
card
);
if
(
err
<
0
)
if
(
err
<
0
)
...
@@ -1386,11 +1354,9 @@ static void ua101_disconnect(struct usb_interface *interface)
...
@@ -1386,11 +1354,9 @@ static void ua101_disconnect(struct usb_interface *interface)
}
}
static
struct
usb_device_id
ua101_ids
[]
=
{
static
struct
usb_device_id
ua101_ids
[]
=
{
#ifdef UA1A_HACK
{
USB_DEVICE
(
0x0582
,
0x0044
)
},
/* UA-1000 high speed */
{
USB_DEVICE
(
0x0582
,
0x0018
)
},
{
USB_DEVICE
(
0x0582
,
0x007d
)
},
/* UA-101 high speed */
#endif
{
USB_DEVICE
(
0x0582
,
0x008d
)
},
/* UA-101 full speed */
{
USB_DEVICE
(
0x0582
,
0x007d
)
},
{
USB_DEVICE
(
0x0582
,
0x008d
)
},
{
}
{
}
};
};
MODULE_DEVICE_TABLE
(
usb
,
ua101_ids
);
MODULE_DEVICE_TABLE
(
usb
,
ua101_ids
);
...
...
sound/usb/usbaudio.c
View file @
156366d3
...
@@ -3386,58 +3386,6 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
...
@@ -3386,58 +3386,6 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
return
0
;
return
0
;
}
}
/*
* Create a stream for an Edirol UA-1000 interface.
*/
static
int
create_ua1000_quirk
(
struct
snd_usb_audio
*
chip
,
struct
usb_interface
*
iface
,
const
struct
snd_usb_audio_quirk
*
quirk
)
{
static
const
struct
audioformat
ua1000_format
=
{
.
format
=
SNDRV_PCM_FORMAT_S32_LE
,
.
fmt_type
=
UAC_FORMAT_TYPE_I
,
.
altsetting
=
1
,
.
altset_idx
=
1
,
.
attributes
=
0
,
.
rates
=
SNDRV_PCM_RATE_CONTINUOUS
,
};
struct
usb_host_interface
*
alts
;
struct
usb_interface_descriptor
*
altsd
;
struct
audioformat
*
fp
;
int
stream
,
err
;
if
(
iface
->
num_altsetting
!=
2
)
return
-
ENXIO
;
alts
=
&
iface
->
altsetting
[
1
];
altsd
=
get_iface_desc
(
alts
);
if
(
alts
->
extralen
!=
11
||
alts
->
extra
[
1
]
!=
USB_DT_CS_INTERFACE
||
altsd
->
bNumEndpoints
!=
1
)
return
-
ENXIO
;
fp
=
kmemdup
(
&
ua1000_format
,
sizeof
(
*
fp
),
GFP_KERNEL
);
if
(
!
fp
)
return
-
ENOMEM
;
fp
->
channels
=
alts
->
extra
[
4
];
fp
->
iface
=
altsd
->
bInterfaceNumber
;
fp
->
endpoint
=
get_endpoint
(
alts
,
0
)
->
bEndpointAddress
;
fp
->
ep_attr
=
get_endpoint
(
alts
,
0
)
->
bmAttributes
;
fp
->
datainterval
=
parse_datainterval
(
chip
,
alts
);
fp
->
maxpacksize
=
le16_to_cpu
(
get_endpoint
(
alts
,
0
)
->
wMaxPacketSize
);
fp
->
rate_max
=
fp
->
rate_min
=
combine_triple
(
&
alts
->
extra
[
8
]);
stream
=
(
fp
->
endpoint
&
USB_DIR_IN
)
?
SNDRV_PCM_STREAM_CAPTURE
:
SNDRV_PCM_STREAM_PLAYBACK
;
err
=
add_audio_endpoint
(
chip
,
stream
,
fp
);
if
(
err
<
0
)
{
kfree
(
fp
);
return
err
;
}
/* FIXME: playback must be synchronized to capture */
usb_set_interface
(
chip
->
dev
,
fp
->
iface
,
0
);
return
0
;
}
static
int
snd_usb_create_quirk
(
struct
snd_usb_audio
*
chip
,
static
int
snd_usb_create_quirk
(
struct
snd_usb_audio
*
chip
,
struct
usb_interface
*
iface
,
struct
usb_interface
*
iface
,
const
struct
snd_usb_audio_quirk
*
quirk
);
const
struct
snd_usb_audio_quirk
*
quirk
);
...
@@ -3686,7 +3634,6 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
...
@@ -3686,7 +3634,6 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
[
QUIRK_MIDI_CME
]
=
create_any_midi_quirk
,
[
QUIRK_MIDI_CME
]
=
create_any_midi_quirk
,
[
QUIRK_AUDIO_STANDARD_INTERFACE
]
=
create_standard_audio_quirk
,
[
QUIRK_AUDIO_STANDARD_INTERFACE
]
=
create_standard_audio_quirk
,
[
QUIRK_AUDIO_FIXED_ENDPOINT
]
=
create_fixed_stream_quirk
,
[
QUIRK_AUDIO_FIXED_ENDPOINT
]
=
create_fixed_stream_quirk
,
[
QUIRK_AUDIO_EDIROL_UA1000
]
=
create_ua1000_quirk
,
[
QUIRK_AUDIO_EDIROL_UAXX
]
=
create_uaxx_quirk
,
[
QUIRK_AUDIO_EDIROL_UAXX
]
=
create_uaxx_quirk
,
[
QUIRK_AUDIO_ALIGN_TRANSFER
]
=
create_align_transfer_quirk
[
QUIRK_AUDIO_ALIGN_TRANSFER
]
=
create_align_transfer_quirk
};
};
...
...
sound/usb/usbaudio.h
View file @
156366d3
...
@@ -75,7 +75,6 @@ enum quirk_type {
...
@@ -75,7 +75,6 @@ enum quirk_type {
QUIRK_MIDI_US122L
,
QUIRK_MIDI_US122L
,
QUIRK_AUDIO_STANDARD_INTERFACE
,
QUIRK_AUDIO_STANDARD_INTERFACE
,
QUIRK_AUDIO_FIXED_ENDPOINT
,
QUIRK_AUDIO_FIXED_ENDPOINT
,
QUIRK_AUDIO_EDIROL_UA1000
,
QUIRK_AUDIO_EDIROL_UAXX
,
QUIRK_AUDIO_EDIROL_UAXX
,
QUIRK_AUDIO_ALIGN_TRANSFER
,
QUIRK_AUDIO_ALIGN_TRANSFER
,
...
@@ -112,7 +111,7 @@ struct snd_usb_midi_endpoint_info {
...
@@ -112,7 +111,7 @@ struct snd_usb_midi_endpoint_info {
/* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */
/* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */
/* for QUIRK_AUDIO_EDIROL_UA
700_UA25/UA1000
, data is NULL */
/* for QUIRK_AUDIO_EDIROL_UA
XX
, data is NULL */
/* for QUIRK_IGNORE_INTERFACE, data is NULL */
/* for QUIRK_IGNORE_INTERFACE, data is NULL */
...
...
sound/usb/usbquirks.h
View file @
156366d3
...
@@ -1015,36 +1015,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
...
@@ -1015,36 +1015,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
}
}
},
},
{
USB_DEVICE
(
0x0582
,
0x0044
),
.
driver_info
=
(
unsigned
long
)
&
(
const
struct
snd_usb_audio_quirk
)
{
.
vendor_name
=
"Roland"
,
.
product_name
=
"UA-1000"
,
.
ifnum
=
QUIRK_ANY_INTERFACE
,
.
type
=
QUIRK_COMPOSITE
,
.
data
=
(
const
struct
snd_usb_audio_quirk
[])
{
{
.
ifnum
=
1
,
.
type
=
QUIRK_AUDIO_EDIROL_UA1000
},
{
.
ifnum
=
2
,
.
type
=
QUIRK_AUDIO_EDIROL_UA1000
},
{
.
ifnum
=
3
,
.
type
=
QUIRK_MIDI_FIXED_ENDPOINT
,
.
data
=
&
(
const
struct
snd_usb_midi_endpoint_info
)
{
.
out_cables
=
0x0003
,
.
in_cables
=
0x0003
}
},
{
.
ifnum
=
-
1
}
}
}
},
{
{
/* has ID 0x0049 when not in "Advanced Driver" mode */
/* has ID 0x0049 when not in "Advanced Driver" mode */
USB_DEVICE
(
0x0582
,
0x0047
),
USB_DEVICE
(
0x0582
,
0x0047
),
...
...
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