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
72df1a80
Commit
72df1a80
authored
Sep 16, 2002
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
USB: convert the drivers/usb/class files to the new USB driver model.
parent
f61fbc71
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
97 additions
and
62 deletions
+97
-62
drivers/usb/class/audio.c
drivers/usb/class/audio.c
+26
-15
drivers/usb/class/bluetty.c
drivers/usb/class/bluetty.c
+17
-14
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.c
+18
-12
drivers/usb/class/usb-midi.c
drivers/usb/class/usb-midi.c
+24
-13
drivers/usb/class/usblp.c
drivers/usb/class/usblp.c
+12
-8
No files found.
drivers/usb/class/audio.c
View file @
72df1a80
...
...
@@ -2740,9 +2740,9 @@ static /*const*/ struct file_operations usb_audio_fops = {
/* --------------------------------------------------------------------- */
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_
device
*
dev
,
void
*
ptr
);
static
int
usb_audio_probe
(
struct
usb_interface
*
iface
,
const
struct
usb_device_id
*
id
);
static
void
usb_audio_disconnect
(
struct
usb_
interface
*
iface
);
static
struct
usb_device_id
usb_audio_ids
[]
=
{
{
.
match_flags
=
(
USB_DEVICE_ID_MATCH_INT_CLASS
|
USB_DEVICE_ID_MATCH_INT_SUBCLASS
),
...
...
@@ -2756,7 +2756,6 @@ static struct usb_driver usb_audio_driver = {
.
name
=
"audio"
,
.
probe
=
usb_audio_probe
,
.
disconnect
=
usb_audio_disconnect
,
.
driver_list
=
LIST_HEAD_INIT
(
usb_audio_driver
.
driver_list
),
.
id_table
=
usb_audio_ids
,
};
...
...
@@ -3643,7 +3642,7 @@ static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *b
list_add_tail
(
&
ms
->
list
,
&
s
->
mixerlist
);
}
static
void
*
usb_audio_parsecontrol
(
struct
usb_device
*
dev
,
unsigned
char
*
buffer
,
unsigned
int
buflen
,
unsigned
int
ctrlif
)
static
struct
usb_audio_state
*
usb_audio_parsecontrol
(
struct
usb_device
*
dev
,
unsigned
char
*
buffer
,
unsigned
int
buflen
,
unsigned
int
ctrlif
)
{
struct
usb_audio_state
*
s
;
struct
usb_config_descriptor
*
config
=
dev
->
actconfig
;
...
...
@@ -3766,10 +3765,12 @@ static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffe
/* we only care for the currently active configuration */
static
void
*
usb_audio_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
)
static
int
usb_audio_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
dev
=
interface_to_usbdev
(
intf
);
struct
usb_config_descriptor
*
config
=
dev
->
actconfig
;
struct
usb_audio_state
*
s
;
unsigned
char
*
buffer
;
unsigned
char
buf
[
8
];
unsigned
int
i
,
buflen
;
...
...
@@ -3789,39 +3790,47 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
if
(
usb_set_configuration
(
dev
,
config
->
bConfigurationValue
)
<
0
)
{
printk
(
KERN_ERR
"usbaudio: set_configuration failed (ConfigValue 0x%x)
\n
"
,
config
->
bConfigurationValue
);
return
NULL
;
return
-
EIO
;
}
ret
=
usb_get_descriptor
(
dev
,
USB_DT_CONFIG
,
i
,
buf
,
8
);
if
(
ret
<
0
)
{
printk
(
KERN_ERR
"usbaudio: cannot get first 8 bytes of config descriptor %d of device %d (error %d)
\n
"
,
i
,
dev
->
devnum
,
ret
);
return
NULL
;
return
-
EIO
;
}
if
(
buf
[
1
]
!=
USB_DT_CONFIG
||
buf
[
0
]
<
9
)
{
printk
(
KERN_ERR
"usbaudio: invalid config descriptor %d of device %d
\n
"
,
i
,
dev
->
devnum
);
return
NULL
;
return
-
EIO
;
}
buflen
=
buf
[
2
]
|
(
buf
[
3
]
<<
8
);
if
(
!
(
buffer
=
kmalloc
(
buflen
,
GFP_KERNEL
)))
return
NULL
;
return
-
ENOMEM
;
ret
=
usb_get_descriptor
(
dev
,
USB_DT_CONFIG
,
i
,
buffer
,
buflen
);
if
(
ret
<
0
)
{
kfree
(
buffer
);
printk
(
KERN_ERR
"usbaudio: cannot get config descriptor %d of device %d (error %d)
\n
"
,
i
,
dev
->
devnum
,
ret
);
return
NULL
;
return
-
EIO
;
}
s
=
usb_audio_parsecontrol
(
dev
,
buffer
,
buflen
,
intf
->
altsetting
->
bInterfaceNumber
);
if
(
s
)
{
dev_set_drvdata
(
&
intf
->
dev
,
s
);
return
0
;
}
return
usb_audio_parsecontrol
(
dev
,
buffer
,
buflen
,
ifnum
)
;
return
-
ENODEV
;
}
/* a revoke facility would make things simpler */
static
void
usb_audio_disconnect
(
struct
usb_
device
*
dev
,
void
*
ptr
)
static
void
usb_audio_disconnect
(
struct
usb_
interface
*
intf
)
{
struct
usb_audio_state
*
s
=
(
struct
usb_audio_state
*
)
ptr
;
struct
usb_audio_state
*
s
=
dev_get_drvdata
(
&
intf
->
dev
)
;
struct
list_head
*
list
;
struct
usb_audiodev
*
as
;
struct
usb_mixerdev
*
ms
;
if
(
!
s
)
return
;
/* we get called with -1 for every audiostreaming interface registered */
if
(
s
==
(
struct
usb_audio_state
*
)
-
1
)
{
dprintk
((
KERN_DEBUG
"usbaudio: note, usb_audio_disconnect called with -1
\n
"
));
...
...
@@ -3835,6 +3844,8 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
list_del
(
&
s
->
audiodev
);
INIT_LIST_HEAD
(
&
s
->
audiodev
);
s
->
usbdev
=
NULL
;
dev_set_drvdata
(
&
intf
->
dev
,
NULL
);
/* deregister all audio and mixer devices, so no new processes can open this device */
for
(
list
=
s
->
audiolist
.
next
;
list
!=
&
s
->
audiolist
;
list
=
list
->
next
)
{
as
=
list_entry
(
list
,
struct
usb_audiodev
,
list
);
...
...
drivers/usb/class/bluetty.c
View file @
72df1a80
...
...
@@ -221,9 +221,9 @@ static void bluetooth_ctrl_callback (struct urb *urb);
static
void
bluetooth_read_bulk_callback
(
struct
urb
*
urb
);
static
void
bluetooth_write_bulk_callback
(
struct
urb
*
urb
);
static
void
*
usb_bluetooth_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
);
static
void
usb_bluetooth_disconnect
(
struct
usb_
device
*
dev
,
void
*
ptr
);
static
int
usb_bluetooth_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
);
static
void
usb_bluetooth_disconnect
(
struct
usb_
interface
*
intf
);
static
struct
usb_device_id
usb_bluetooth_ids
[]
=
{
...
...
@@ -1033,9 +1033,10 @@ static void bluetooth_softint(void *private)
}
static
void
*
usb_bluetooth_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
)
static
int
usb_bluetooth_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
dev
=
interface_to_usbdev
(
intf
);
struct
usb_bluetooth
*
bluetooth
=
NULL
;
struct
usb_interface_descriptor
*
interface
;
struct
usb_endpoint_descriptor
*
endpoint
;
...
...
@@ -1051,7 +1052,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
int
num_bulk_in
=
0
;
int
num_bulk_out
=
0
;
interface
=
&
dev
->
actconfig
->
interface
[
ifnum
].
altsetting
[
0
];
interface
=
&
intf
->
altsetting
[
0
];
control_out_endpoint
=
interface
->
bInterfaceNumber
;
/* find the endpoints that we need */
...
...
@@ -1088,7 +1089,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
(
num_bulk_out
!=
1
)
||
(
num_interrupt_in
!=
1
))
{
dbg
(
"%s - improper number of endpoints. Bluetooth driver not bound."
,
__FUNCTION__
);
return
NULL
;
return
-
EIO
;
}
MOD_INC_USE_COUNT
;
...
...
@@ -1099,13 +1100,13 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
if
(
bluetooth_table
[
minor
])
{
err
(
"No more free Bluetooth devices"
);
MOD_DEC_USE_COUNT
;
return
NULL
;
return
-
ENODEV
;
}
if
(
!
(
bluetooth
=
kmalloc
(
sizeof
(
struct
usb_bluetooth
),
GFP_KERNEL
)))
{
err
(
"Out of memory"
);
MOD_DEC_USE_COUNT
;
return
NULL
;
return
-
ENOMEM
;
}
memset
(
bluetooth
,
0
,
sizeof
(
struct
usb_bluetooth
));
...
...
@@ -1191,7 +1192,9 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
bluetooth_table
[
minor
]
=
bluetooth
;
return
bluetooth
;
/* success */
/* success */
dev_set_drvdata
(
&
intf
->
dev
,
bluetooth
);
return
0
;
probe_error:
if
(
bluetooth
->
read_urb
)
...
...
@@ -1220,15 +1223,16 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
/* free up any memory that we allocated */
kfree
(
bluetooth
);
MOD_DEC_USE_COUNT
;
return
NULL
;
return
-
EIO
;
}
static
void
usb_bluetooth_disconnect
(
struct
usb_
device
*
dev
,
void
*
ptr
)
static
void
usb_bluetooth_disconnect
(
struct
usb_
interface
*
intf
)
{
struct
usb_bluetooth
*
bluetooth
=
(
struct
usb_bluetooth
*
)
ptr
;
struct
usb_bluetooth
*
bluetooth
=
dev_get_drvdata
(
&
intf
->
dev
)
;
int
i
;
dev_set_drvdata
(
&
intf
->
dev
,
NULL
);
if
(
bluetooth
)
{
if
((
bluetooth
->
open_count
)
&&
(
bluetooth
->
tty
))
tty_hangup
(
bluetooth
->
tty
);
...
...
@@ -1274,7 +1278,6 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
/* free up any memory that we allocated */
kfree
(
bluetooth
);
}
else
{
info
(
"device disconnected"
);
}
...
...
drivers/usb/class/cdc-acm.c
View file @
72df1a80
...
...
@@ -507,9 +507,10 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
* USB probe and disconnect routines.
*/
static
void
*
acm_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
)
static
int
acm_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
dev
;
struct
acm
*
acm
;
struct
usb_config_descriptor
*
cfacm
;
struct
usb_interface_descriptor
*
ifcom
,
*
ifdata
;
...
...
@@ -517,6 +518,7 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
int
readsize
,
ctrlsize
,
minor
,
i
;
unsigned
char
*
buf
;
dev
=
interface_to_usbdev
(
intf
);
for
(
i
=
0
;
i
<
dev
->
descriptor
.
bNumConfigurations
;
i
++
)
{
cfacm
=
dev
->
config
+
i
;
...
...
@@ -561,12 +563,12 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
for
(
minor
=
0
;
minor
<
ACM_TTY_MINORS
&&
acm_table
[
minor
];
minor
++
);
if
(
acm_table
[
minor
])
{
err
(
"no more free acm devices"
);
return
NULL
;
return
-
ENODEV
;
}
if
(
!
(
acm
=
kmalloc
(
sizeof
(
struct
acm
),
GFP_KERNEL
)))
{
err
(
"out of memory"
);
return
NULL
;
return
-
ENOMEM
;
}
memset
(
acm
,
0
,
sizeof
(
struct
acm
));
...
...
@@ -583,21 +585,21 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
if
(
!
(
buf
=
kmalloc
(
ctrlsize
+
readsize
+
acm
->
writesize
,
GFP_KERNEL
)))
{
err
(
"out of memory"
);
kfree
(
acm
);
return
NULL
;
return
-
ENOMEM
;
}
acm
->
ctrlurb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
acm
->
ctrlurb
)
{
err
(
"out of memory"
);
kfree
(
acm
);
return
NULL
;
return
-
ENOMEM
;
}
acm
->
readurb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
acm
->
readurb
)
{
err
(
"out of memory"
);
usb_free_urb
(
acm
->
ctrlurb
);
kfree
(
acm
);
return
NULL
;
return
-
ENOMEM
;
}
acm
->
writeurb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
acm
->
writeurb
)
{
...
...
@@ -605,7 +607,7 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
usb_free_urb
(
acm
->
readurb
);
usb_free_urb
(
acm
->
ctrlurb
);
kfree
(
acm
);
return
NULL
;
return
-
ENOMEM
;
}
usb_fill_int_urb
(
acm
->
ctrlurb
,
dev
,
usb_rcvintpipe
(
dev
,
epctrl
->
bEndpointAddress
),
...
...
@@ -631,15 +633,18 @@ static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
usb_driver_claim_interface
(
&
acm_driver
,
acm
->
iface
+
1
,
acm
);
tty_register_devfs
(
&
acm_tty_driver
,
0
,
minor
);
return
acm_table
[
minor
]
=
acm
;
acm_table
[
minor
]
=
acm
;
dev_set_drvdata
(
&
intf
->
dev
,
acm
);
return
0
;
}
return
NULL
;
return
-
EIO
;
}
static
void
acm_disconnect
(
struct
usb_
device
*
dev
,
void
*
ptr
)
static
void
acm_disconnect
(
struct
usb_
interface
*
intf
)
{
struct
acm
*
acm
=
ptr
;
struct
acm
*
acm
=
dev_get_drvdata
(
&
intf
->
dev
)
;
if
(
!
acm
||
!
acm
->
dev
)
{
dbg
(
"disconnect on nonexisting interface"
);
...
...
@@ -647,6 +652,7 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
}
acm
->
dev
=
NULL
;
dev_set_drvdata
(
&
intf
->
dev
,
NULL
);
usb_unlink_urb
(
acm
->
ctrlurb
);
usb_unlink_urb
(
acm
->
readurb
);
...
...
drivers/usb/class/usb-midi.c
View file @
72df1a80
...
...
@@ -2020,13 +2020,16 @@ static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_m
/* ------------------------------------------------------------------------- */
static
void
*
usb_midi_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
)
static
int
usb_midi_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_midi_state
*
s
;
struct
usb_device
*
dev
=
interface_to_usbdev
(
intf
);
int
ifnum
=
intf
->
altsetting
->
bInterfaceNumber
;
s
=
(
struct
usb_midi_state
*
)
kmalloc
(
sizeof
(
struct
usb_midi_state
),
GFP_KERNEL
);
if
(
!
s
)
{
return
NULL
;
}
if
(
!
s
)
return
-
ENOMEM
;
memset
(
s
,
0
,
sizeof
(
struct
usb_midi_state
)
);
INIT_LIST_HEAD
(
&
s
->
midiDevList
);
...
...
@@ -2042,7 +2045,7 @@ static void *usb_midi_probe(struct usb_device *dev, unsigned int ifnum,
detect_vendor_specific_device
(
dev
,
ifnum
,
s
)
&&
detect_yamaha_device
(
dev
,
ifnum
,
s
)
)
{
kfree
(
s
);
return
NULL
;
return
-
EIO
;
}
down
(
&
open_sem
);
...
...
@@ -2053,16 +2056,20 @@ static void *usb_midi_probe(struct usb_device *dev, unsigned int ifnum,
MOD_INC_USE_COUNT
;
#endif
return
s
;
dev_set_drvdata
(
&
intf
->
dev
,
s
);
return
0
;
}
static
void
usb_midi_disconnect
(
struct
usb_
device
*
dev
,
void
*
ptr
)
static
void
usb_midi_disconnect
(
struct
usb_
interface
*
intf
)
{
struct
usb_midi_state
*
s
=
(
struct
usb_midi_state
*
)
ptr
;
struct
usb_midi_state
*
s
=
dev_get_drvdata
(
&
intf
->
dev
)
;
struct
list_head
*
list
;
struct
usb_mididev
*
m
;
if
(
!
s
)
return
;
if
(
s
==
(
struct
usb_midi_state
*
)
-
1
)
{
return
;
}
...
...
@@ -2073,6 +2080,7 @@ static void usb_midi_disconnect(struct usb_device *dev, void *ptr)
list_del
(
&
s
->
mididev
);
INIT_LIST_HEAD
(
&
s
->
mididev
);
s
->
usbdev
=
NULL
;
dev_set_drvdata
(
&
intf
->
dev
,
NULL
);
for
(
list
=
s
->
midiDevList
.
next
;
list
!=
&
s
->
midiDevList
;
list
=
list
->
next
)
{
m
=
list_entry
(
list
,
struct
usb_mididev
,
list
);
...
...
@@ -2092,14 +2100,17 @@ static void usb_midi_disconnect(struct usb_device *dev, void *ptr)
return
;
}
/* we want to look at all devices by hand */
static
struct
usb_device_id
id_table
[]
=
{
{.
driver_info
=
42
},
{}
};
static
struct
usb_driver
usb_midi_driver
=
{
.
name
=
"midi"
,
.
probe
=
usb_midi_probe
,
.
disconnect
=
usb_midi_disconnect
,
.
id_table
=
NULL
,
/* check all devices */
.
driver_list
=
LIST_HEAD_INIT
(
usb_midi_driver
.
driver_list
)
.
name
=
"midi"
,
.
probe
=
usb_midi_probe
,
.
disconnect
=
usb_midi_disconnect
,
.
id_table
=
id_table
,
};
/* ------------------------------------------------------------------------- */
...
...
drivers/usb/class/usblp.c
View file @
72df1a80
...
...
@@ -795,9 +795,10 @@ static struct file_operations usblp_fops = {
.
release
=
usblp_release
,
};
static
void
*
usblp_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
)
static
int
usblp_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
dev
=
interface_to_usbdev
(
intf
);
struct
usblp
*
usblp
=
0
;
int
protocol
;
int
retval
;
...
...
@@ -813,7 +814,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
usblp
->
dev
=
dev
;
init_MUTEX
(
&
usblp
->
sem
);
init_waitqueue_head
(
&
usblp
->
wait
);
usblp
->
ifnum
=
i
fnum
;
usblp
->
ifnum
=
i
ntf
->
altsetting
->
bInterfaceNumber
;
retval
=
usb_register_dev
(
&
usblp_fops
,
USBLP_MINOR_BASE
,
1
,
&
usblp
->
minor
);
if
(
retval
)
{
...
...
@@ -886,12 +887,14 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
info
(
"usblp%d: USB %sdirectional printer dev %d "
"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X"
,
usblp
->
minor
,
usblp
->
bidir
?
"Bi"
:
"Uni"
,
dev
->
devnum
,
ifnum
,
usblp
->
minor
,
usblp
->
bidir
?
"Bi"
:
"Uni"
,
dev
->
devnum
,
usblp
->
ifnum
,
usblp
->
protocol
[
usblp
->
current_protocol
].
alt_setting
,
usblp
->
current_protocol
,
usblp
->
dev
->
descriptor
.
idVendor
,
usblp
->
dev
->
descriptor
.
idProduct
);
return
usblp
;
dev_set_drvdata
(
&
intf
->
dev
,
usblp
);
return
0
;
abort_minor:
usb_deregister_dev
(
1
,
usblp
->
minor
);
...
...
@@ -903,7 +906,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
if
(
usblp
->
device_id_string
)
kfree
(
usblp
->
device_id_string
);
kfree
(
usblp
);
}
return
NULL
;
return
-
EIO
;
}
/*
...
...
@@ -1065,9 +1068,9 @@ static int usblp_cache_device_id_string(struct usblp *usblp)
return
length
;
}
static
void
usblp_disconnect
(
struct
usb_
device
*
dev
,
void
*
ptr
)
static
void
usblp_disconnect
(
struct
usb_
interface
*
intf
)
{
struct
usblp
*
usblp
=
ptr
;
struct
usblp
*
usblp
=
dev_get_drvdata
(
&
intf
->
dev
)
;
if
(
!
usblp
||
!
usblp
->
dev
)
{
err
(
"bogus disconnect"
);
...
...
@@ -1077,6 +1080,7 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr)
down
(
&
usblp
->
sem
);
lock_kernel
();
usblp
->
dev
=
NULL
;
dev_set_drvdata
(
&
intf
->
dev
,
NULL
);
usblp_unlink_urbs
(
usblp
);
...
...
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