Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
5e0ddd07
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
5e0ddd07
编写于
1月 28, 2015
作者:
T
Takashi Iwai
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'topic/line6' into for-next
上级
1001fb81
247d95ee
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
705 addition
and
1105 deletion
+705
-1105
sound/usb/line6/Kconfig
sound/usb/line6/Kconfig
+2
-0
sound/usb/line6/capture.c
sound/usb/line6/capture.c
+39
-184
sound/usb/line6/capture.h
sound/usb/line6/capture.h
+0
-6
sound/usb/line6/driver.c
sound/usb/line6/driver.c
+92
-110
sound/usb/line6/driver.h
sound/usb/line6/driver.h
+5
-5
sound/usb/line6/midi.c
sound/usb/line6/midi.c
+6
-12
sound/usb/line6/midi.h
sound/usb/line6/midi.h
+1
-6
sound/usb/line6/pcm.c
sound/usb/line6/pcm.c
+272
-171
sound/usb/line6/pcm.h
sound/usb/line6/pcm.h
+85
-219
sound/usb/line6/playback.c
sound/usb/line6/playback.c
+66
-218
sound/usb/line6/playback.h
sound/usb/line6/playback.h
+0
-6
sound/usb/line6/pod.c
sound/usb/line6/pod.c
+14
-31
sound/usb/line6/podhd.c
sound/usb/line6/podhd.c
+4
-13
sound/usb/line6/toneport.c
sound/usb/line6/toneport.c
+113
-103
sound/usb/line6/variax.c
sound/usb/line6/variax.c
+6
-21
未找到文件。
sound/usb/line6/Kconfig
浏览文件 @
5e0ddd07
...
...
@@ -29,6 +29,8 @@ config SND_USB_PODHD
config SND_USB_TONEPORT
tristate "TonePort GX, UX1 and UX2 USB support"
select SND_USB_LINE6
select NEW_LEDS
select LEDS_CLASS
help
This is a driver for TonePort GX, UX1 and UX2 devices.
...
...
sound/usb/line6/capture.c
浏览文件 @
5e0ddd07
...
...
@@ -20,26 +20,24 @@
/*
Find a free URB and submit it.
must be called in line6pcm->in.lock context
*/
static
int
submit_audio_in_urb
(
struct
snd_line6_pcm
*
line6pcm
)
{
int
index
;
unsigned
long
flags
;
int
i
,
urb_size
;
int
ret
;
struct
urb
*
urb_in
;
spin_lock_irqsave
(
&
line6pcm
->
lock_audio_in
,
flags
);
index
=
find_first_zero_bit
(
&
line6pcm
->
active_urb_in
,
LINE6_ISO_BUFFERS
);
find_first_zero_bit
(
&
line6pcm
->
in
.
active_urbs
,
LINE6_ISO_BUFFERS
);
if
(
index
<
0
||
index
>=
LINE6_ISO_BUFFERS
)
{
spin_unlock_irqrestore
(
&
line6pcm
->
lock_audio_in
,
flags
);
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"no free URB found
\n
"
);
return
-
EINVAL
;
}
urb_in
=
line6pcm
->
urb_audio_in
[
index
];
urb_in
=
line6pcm
->
in
.
urbs
[
index
];
urb_size
=
0
;
for
(
i
=
0
;
i
<
LINE6_ISO_PACKETS
;
++
i
)
{
...
...
@@ -51,7 +49,7 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
}
urb_in
->
transfer_buffer
=
line6pcm
->
buffer_in
+
line6pcm
->
in
.
buffer
+
index
*
LINE6_ISO_PACKETS
*
line6pcm
->
max_packet_size
;
urb_in
->
transfer_buffer_length
=
urb_size
;
urb_in
->
context
=
line6pcm
;
...
...
@@ -59,81 +57,29 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
ret
=
usb_submit_urb
(
urb_in
,
GFP_ATOMIC
);
if
(
ret
==
0
)
set_bit
(
index
,
&
line6pcm
->
active_urb_in
);
set_bit
(
index
,
&
line6pcm
->
in
.
active_urbs
);
else
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"URB in #%d submission failed (%d)
\n
"
,
index
,
ret
);
spin_unlock_irqrestore
(
&
line6pcm
->
lock_audio_in
,
flags
);
return
0
;
}
/*
Submit all currently available capture URBs.
must be called in line6pcm->in.lock context
*/
int
line6_submit_audio_in_all_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
{
int
ret
,
i
;
int
ret
=
0
,
i
;
for
(
i
=
0
;
i
<
LINE6_ISO_BUFFERS
;
++
i
)
{
ret
=
submit_audio_in_urb
(
line6pcm
);
if
(
ret
<
0
)
return
ret
;
}
return
0
;
}
/*
Unlink all currently active capture URBs.
*/
void
line6_unlink_audio_in_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
{
unsigned
int
i
;
for
(
i
=
LINE6_ISO_BUFFERS
;
i
--
;)
{
if
(
test_bit
(
i
,
&
line6pcm
->
active_urb_in
))
{
if
(
!
test_and_set_bit
(
i
,
&
line6pcm
->
unlink_urb_in
))
{
struct
urb
*
u
=
line6pcm
->
urb_audio_in
[
i
];
usb_unlink_urb
(
u
);
}
}
}
}
/*
Wait until unlinking of all currently active capture URBs has been
finished.
*/
void
line6_wait_clear_audio_in_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
{
int
timeout
=
HZ
;
unsigned
int
i
;
int
alive
;
do
{
alive
=
0
;
for
(
i
=
LINE6_ISO_BUFFERS
;
i
--
;)
{
if
(
test_bit
(
i
,
&
line6pcm
->
active_urb_in
))
alive
++
;
}
if
(
!
alive
)
break
;
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
1
);
}
while
(
--
timeout
>
0
);
if
(
alive
)
snd_printk
(
KERN_ERR
"timeout: still %d active urbs..
\n
"
,
alive
);
}
}
/*
Unlink all currently active capture URBs, and wait for finishing.
*/
void
line6_unlink_wait_clear_audio_in_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
{
line6_unlink_audio_in_urbs
(
line6pcm
);
line6_wait_clear_audio_in_urbs
(
line6pcm
);
return
ret
;
}
/*
...
...
@@ -150,18 +96,18 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
if
(
runtime
==
NULL
)
return
;
if
(
line6pcm
->
pos_in
_done
+
frames
>
runtime
->
buffer_size
)
{
if
(
line6pcm
->
in
.
pos
_done
+
frames
>
runtime
->
buffer_size
)
{
/*
The transferred area goes over buffer boundary,
copy two separate chunks.
*/
int
len
;
len
=
runtime
->
buffer_size
-
line6pcm
->
pos_in
_done
;
len
=
runtime
->
buffer_size
-
line6pcm
->
in
.
pos
_done
;
if
(
len
>
0
)
{
memcpy
(
runtime
->
dma_area
+
line6pcm
->
pos_in
_done
*
bytes_per_frame
,
fbuf
,
line6pcm
->
in
.
pos
_done
*
bytes_per_frame
,
fbuf
,
len
*
bytes_per_frame
);
memcpy
(
runtime
->
dma_area
,
fbuf
+
len
*
bytes_per_frame
,
(
frames
-
len
)
*
bytes_per_frame
);
...
...
@@ -173,12 +119,12 @@ void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
}
else
{
/* copy single chunk */
memcpy
(
runtime
->
dma_area
+
line6pcm
->
pos_in
_done
*
bytes_per_frame
,
fbuf
,
fsize
);
line6pcm
->
in
.
pos
_done
*
bytes_per_frame
,
fbuf
,
fsize
);
}
line6pcm
->
pos_in
_done
+=
frames
;
if
(
line6pcm
->
pos_in
_done
>=
runtime
->
buffer_size
)
line6pcm
->
pos_in
_done
-=
runtime
->
buffer_size
;
line6pcm
->
in
.
pos
_done
+=
frames
;
if
(
line6pcm
->
in
.
pos
_done
>=
runtime
->
buffer_size
)
line6pcm
->
in
.
pos
_done
-=
runtime
->
buffer_size
;
}
void
line6_capture_check_period
(
struct
snd_line6_pcm
*
line6pcm
,
int
length
)
...
...
@@ -186,19 +132,15 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
struct
snd_pcm_substream
*
substream
=
get_substream
(
line6pcm
,
SNDRV_PCM_STREAM_CAPTURE
);
line6pcm
->
bytes_in
+=
length
;
if
(
line6pcm
->
bytes_in
>=
line6pcm
->
period_in
)
{
line6pcm
->
bytes_in
%=
line6pcm
->
period_in
;
line6pcm
->
in
.
bytes
+=
length
;
if
(
line6pcm
->
in
.
bytes
>=
line6pcm
->
in
.
period
)
{
line6pcm
->
in
.
bytes
%=
line6pcm
->
in
.
period
;
spin_unlock
(
&
line6pcm
->
in
.
lock
);
snd_pcm_period_elapsed
(
substream
);
spin_lock
(
&
line6pcm
->
in
.
lock
);
}
}
void
line6_free_capture_buffer
(
struct
snd_line6_pcm
*
line6pcm
)
{
kfree
(
line6pcm
->
buffer_in
);
line6pcm
->
buffer_in
=
NULL
;
}
/*
* Callback for completed capture URB.
*/
...
...
@@ -209,14 +151,14 @@ static void audio_in_callback(struct urb *urb)
struct
snd_line6_pcm
*
line6pcm
=
(
struct
snd_line6_pcm
*
)
urb
->
context
;
line6pcm
->
last_frame_in
=
urb
->
start_frame
;
line6pcm
->
in
.
last_frame
=
urb
->
start_frame
;
/* find index of URB */
for
(
index
=
0
;
index
<
LINE6_ISO_BUFFERS
;
++
index
)
if
(
urb
==
line6pcm
->
urb_audio_in
[
index
])
if
(
urb
==
line6pcm
->
in
.
urbs
[
index
])
break
;
spin_lock_irqsave
(
&
line6pcm
->
lock_audio_in
,
flags
);
spin_lock_irqsave
(
&
line6pcm
->
in
.
lock
,
flags
);
for
(
i
=
0
;
i
<
LINE6_ISO_PACKETS
;
++
i
)
{
char
*
fbuf
;
...
...
@@ -243,27 +185,26 @@ static void audio_in_callback(struct urb *urb)
line6pcm
->
prev_fbuf
=
fbuf
;
line6pcm
->
prev_fsize
=
fsize
;
if
(
!
(
line6pcm
->
flags
&
LINE6_BITS_PCM_IMPULSE
))
if
(
test_bit
(
LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM
,
&
line6pcm
->
flags
)
&&
(
fsize
>
0
)
)
line6_capture_copy
(
line6pcm
,
fbuf
,
fsize
);
if
(
!
test_bit
(
LINE6_STREAM_IMPULSE
,
&
line6pcm
->
in
.
running
)
&&
test_bit
(
LINE6_STREAM_PCM
,
&
line6pcm
->
in
.
running
)
&&
fsize
>
0
)
line6_capture_copy
(
line6pcm
,
fbuf
,
fsize
);
}
clear_bit
(
index
,
&
line6pcm
->
active_urb_in
);
clear_bit
(
index
,
&
line6pcm
->
in
.
active_urbs
);
if
(
test_and_clear_bit
(
index
,
&
line6pcm
->
unlink_urb_in
))
if
(
test_and_clear_bit
(
index
,
&
line6pcm
->
in
.
unlink_urbs
))
shutdown
=
1
;
spin_unlock_irqrestore
(
&
line6pcm
->
lock_audio_in
,
flags
);
if
(
!
shutdown
)
{
submit_audio_in_urb
(
line6pcm
);
if
(
!
(
line6pcm
->
flags
&
LINE6_BITS_PCM_IMPULSE
))
if
(
test_bit
(
LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM
,
&
line6pcm
->
flags
))
line6_capture_check_period
(
line6pcm
,
length
);
if
(
!
test_bit
(
LINE6_STREAM_IMPULSE
,
&
line6pcm
->
in
.
running
)
&&
test_bit
(
LINE6_STREAM_PCM
,
&
line6pcm
->
in
.
running
))
line6_capture_check_period
(
line6pcm
,
length
);
}
spin_unlock_irqrestore
(
&
line6pcm
->
in
.
lock
,
flags
);
}
/* open capture callback */
...
...
@@ -290,102 +231,16 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream)
return
0
;
}
/* hw_params capture callback */
static
int
snd_line6_capture_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
hw_params
)
{
int
ret
;
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
/* -- Florian Demski [FD] */
/* don't ask me why, but this fixes the bug on my machine */
if
(
line6pcm
==
NULL
)
{
if
(
substream
->
pcm
==
NULL
)
return
-
ENOMEM
;
if
(
substream
->
pcm
->
private_data
==
NULL
)
return
-
ENOMEM
;
substream
->
private_data
=
substream
->
pcm
->
private_data
;
line6pcm
=
snd_pcm_substream_chip
(
substream
);
}
/* -- [FD] end */
ret
=
line6_pcm_acquire
(
line6pcm
,
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER
);
if
(
ret
<
0
)
return
ret
;
ret
=
snd_pcm_lib_malloc_pages
(
substream
,
params_buffer_bytes
(
hw_params
));
if
(
ret
<
0
)
{
line6_pcm_release
(
line6pcm
,
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER
);
return
ret
;
}
line6pcm
->
period_in
=
params_period_bytes
(
hw_params
);
return
0
;
}
/* hw_free capture callback */
static
int
snd_line6_capture_hw_free
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
line6_pcm_release
(
line6pcm
,
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER
);
return
snd_pcm_lib_free_pages
(
substream
);
}
/* trigger callback */
int
snd_line6_capture_trigger
(
struct
snd_line6_pcm
*
line6pcm
,
int
cmd
)
{
int
err
;
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
case
SNDRV_PCM_TRIGGER_RESUME
:
err
=
line6_pcm_acquire
(
line6pcm
,
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM
);
if
(
err
<
0
)
return
err
;
break
;
case
SNDRV_PCM_TRIGGER_STOP
:
case
SNDRV_PCM_TRIGGER_SUSPEND
:
err
=
line6_pcm_release
(
line6pcm
,
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM
);
if
(
err
<
0
)
return
err
;
break
;
default:
return
-
EINVAL
;
}
return
0
;
}
/* capture pointer callback */
static
snd_pcm_uframes_t
snd_line6_capture_pointer
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
return
line6pcm
->
pos_in_done
;
}
/* capture operators */
struct
snd_pcm_ops
snd_line6_capture_ops
=
{
.
open
=
snd_line6_capture_open
,
.
close
=
snd_line6_capture_close
,
.
ioctl
=
snd_pcm_lib_ioctl
,
.
hw_params
=
snd_line6_
capture_
hw_params
,
.
hw_free
=
snd_line6_
capture_
hw_free
,
.
hw_params
=
snd_line6_hw_params
,
.
hw_free
=
snd_line6_hw_free
,
.
prepare
=
snd_line6_prepare
,
.
trigger
=
snd_line6_trigger
,
.
pointer
=
snd_line6_
capture_
pointer
,
.
pointer
=
snd_line6_pointer
,
};
int
line6_create_audio_in_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
...
...
@@ -398,7 +253,7 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
struct
urb
*
urb
;
/* URB for audio in: */
urb
=
line6pcm
->
urb_audio_in
[
i
]
=
urb
=
line6pcm
->
in
.
urbs
[
i
]
=
usb_alloc_urb
(
LINE6_ISO_PACKETS
,
GFP_KERNEL
);
if
(
urb
==
NULL
)
...
...
sound/usb/line6/capture.h
浏览文件 @
5e0ddd07
...
...
@@ -24,12 +24,6 @@ extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
extern
void
line6_capture_check_period
(
struct
snd_line6_pcm
*
line6pcm
,
int
length
);
extern
int
line6_create_audio_in_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
void
line6_free_capture_buffer
(
struct
snd_line6_pcm
*
line6pcm
);
extern
int
line6_submit_audio_in_all_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
void
line6_unlink_audio_in_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
void
line6_unlink_wait_clear_audio_in_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
void
line6_wait_clear_audio_in_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
int
snd_line6_capture_trigger
(
struct
snd_line6_pcm
*
line6pcm
,
int
cmd
);
#endif
sound/usb/line6/driver.c
浏览文件 @
5e0ddd07
...
...
@@ -412,27 +412,13 @@ int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
}
EXPORT_SYMBOL_GPL
(
line6_read_serial_number
);
/*
No operation (i.e., unsupported).
*/
ssize_t
line6_nop_read
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
return
0
;
}
EXPORT_SYMBOL_GPL
(
line6_nop_read
);
/*
Card destructor.
*/
static
void
line6_destruct
(
struct
snd_card
*
card
)
{
struct
usb_line6
*
line6
=
card
->
private_data
;
struct
usb_device
*
usbdev
;
if
(
!
line6
)
return
;
usbdev
=
line6
->
usbdev
;
struct
usb_device
*
usbdev
=
line6
->
usbdev
;
/* free buffer memory first: */
kfree
(
line6
->
buffer_message
);
...
...
@@ -441,82 +427,96 @@ static void line6_destruct(struct snd_card *card)
/* then free URBs: */
usb_free_urb
(
line6
->
urb_listen
);
/* free interface data: */
kfree
(
line6
);
/* decrement reference counters: */
usb_put_dev
(
usbdev
);
}
/* get data from endpoint descriptor (see usb_maxpacket): */
static
void
line6_get_interval
(
struct
usb_line6
*
line6
)
{
struct
usb_device
*
usbdev
=
line6
->
usbdev
;
struct
usb_host_endpoint
*
ep
;
unsigned
pipe
=
usb_rcvintpipe
(
usbdev
,
line6
->
properties
->
ep_ctrl_r
);
unsigned
epnum
=
usb_pipeendpoint
(
pipe
);
ep
=
usbdev
->
ep_in
[
epnum
];
if
(
ep
)
{
line6
->
interval
=
ep
->
desc
.
bInterval
;
line6
->
max_packet_size
=
le16_to_cpu
(
ep
->
desc
.
wMaxPacketSize
);
}
else
{
dev_err
(
line6
->
ifcdev
,
"endpoint not available, using fallback values"
);
line6
->
interval
=
LINE6_FALLBACK_INTERVAL
;
line6
->
max_packet_size
=
LINE6_FALLBACK_MAXPACKETSIZE
;
}
}
static
int
line6_init_cap_control
(
struct
usb_line6
*
line6
)
{
int
ret
;
/* initialize USB buffers: */
line6
->
buffer_listen
=
kmalloc
(
LINE6_BUFSIZE_LISTEN
,
GFP_KERNEL
);
if
(
!
line6
->
buffer_listen
)
return
-
ENOMEM
;
line6
->
buffer_message
=
kmalloc
(
LINE6_MESSAGE_MAXLEN
,
GFP_KERNEL
);
if
(
!
line6
->
buffer_message
)
return
-
ENOMEM
;
line6
->
urb_listen
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
line6
->
urb_listen
)
return
-
ENOMEM
;
ret
=
line6_start_listen
(
line6
);
if
(
ret
<
0
)
{
dev_err
(
line6
->
ifcdev
,
"cannot start listening: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
/*
Probe USB device.
*/
int
line6_probe
(
struct
usb_interface
*
interface
,
struct
usb_line6
*
line6
,
const
struct
usb_device_id
*
id
,
const
struct
line6_properties
*
properties
,
int
(
*
private_init
)(
struct
usb_interface
*
,
struct
usb_line6
*
))
int
(
*
private_init
)(
struct
usb_line6
*
,
const
struct
usb_device_id
*
id
),
size_t
data_size
)
{
struct
usb_device
*
usbdev
=
interface_to_usbdev
(
interface
);
struct
snd_card
*
card
;
struct
usb_line6
*
line6
;
int
interface_number
;
int
ret
;
/* we don't handle multiple configurations */
if
(
usbdev
->
descriptor
.
bNumConfigurations
!=
1
)
{
ret
=
-
ENODEV
;
goto
err_put
;
}
/* initialize device info: */
dev_info
(
&
interface
->
dev
,
"Line 6 %s found
\n
"
,
properties
->
name
);
if
(
WARN_ON
(
data_size
<
sizeof
(
*
line6
)))
return
-
EINVAL
;
/* query interface number */
interface_number
=
interface
->
cur_altsetting
->
desc
.
bInterfaceNumber
;
/* we don't handle multiple configurations */
if
(
usbdev
->
descriptor
.
bNumConfigurations
!=
1
)
return
-
ENODEV
;
ret
=
usb_set_interface
(
usbdev
,
interface_number
,
properties
->
altsetting
);
if
(
ret
<
0
)
{
dev_err
(
&
interface
->
dev
,
"set_interface failed
\n
"
);
goto
err_put
;
}
ret
=
snd_card_new
(
&
interface
->
dev
,
SNDRV_DEFAULT_IDX1
,
SNDRV_DEFAULT_STR1
,
THIS_MODULE
,
data_size
,
&
card
);
if
(
ret
<
0
)
return
ret
;
/* store basic data: */
line6
=
card
->
private_data
;
line6
->
card
=
card
;
line6
->
properties
=
properties
;
line6
->
usbdev
=
usbdev
;
line6
->
ifcdev
=
&
interface
->
dev
;
/* get data from endpoint descriptor (see usb_maxpacket): */
{
struct
usb_host_endpoint
*
ep
;
unsigned
pipe
=
usb_rcvintpipe
(
usbdev
,
properties
->
ep_ctrl_r
);
unsigned
epnum
=
usb_pipeendpoint
(
pipe
);
ep
=
usbdev
->
ep_in
[
epnum
];
if
(
ep
!=
NULL
)
{
line6
->
interval
=
ep
->
desc
.
bInterval
;
line6
->
max_packet_size
=
le16_to_cpu
(
ep
->
desc
.
wMaxPacketSize
);
}
else
{
line6
->
interval
=
LINE6_FALLBACK_INTERVAL
;
line6
->
max_packet_size
=
LINE6_FALLBACK_MAXPACKETSIZE
;
dev_err
(
line6
->
ifcdev
,
"endpoint not available, using fallback values"
);
}
}
ret
=
snd_card_new
(
line6
->
ifcdev
,
SNDRV_DEFAULT_IDX1
,
SNDRV_DEFAULT_STR1
,
THIS_MODULE
,
0
,
&
card
);
if
(
ret
<
0
)
goto
err_put
;
line6
->
card
=
card
;
strcpy
(
card
->
id
,
line6
->
properties
->
id
);
strcpy
(
card
->
id
,
properties
->
id
);
strcpy
(
card
->
driver
,
DRIVER_NAME
);
strcpy
(
card
->
shortname
,
line6
->
properties
->
name
);
sprintf
(
card
->
longname
,
"Line 6 %s at USB %s"
,
line6
->
properties
->
name
,
strcpy
(
card
->
shortname
,
properties
->
name
);
sprintf
(
card
->
longname
,
"Line 6 %s at USB %s"
,
properties
->
name
,
dev_name
(
line6
->
ifcdev
));
card
->
private_data
=
line6
;
card
->
private_free
=
line6_destruct
;
usb_set_intfdata
(
interface
,
line6
);
...
...
@@ -524,52 +524,43 @@ int line6_probe(struct usb_interface *interface,
/* increment reference counters: */
usb_get_dev
(
usbdev
);
if
(
properties
->
capabilities
&
LINE6_CAP_CONTROL
)
{
/* initialize USB buffers: */
line6
->
buffer_listen
=
kmalloc
(
LINE6_BUFSIZE_LISTEN
,
GFP_KERNEL
);
if
(
line6
->
buffer_listen
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
err_destruct
;
}
/* initialize device info: */
dev_info
(
&
interface
->
dev
,
"Line 6 %s found
\n
"
,
properties
->
name
);
line6
->
buffer_message
=
kmalloc
(
LINE6_MESSAGE_MAXLEN
,
GFP_KERNEL
);
if
(
line6
->
buffer_message
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
err_destruct
;
}
/* query interface number */
interface_number
=
interface
->
cur_altsetting
->
desc
.
bInterfaceNumber
;
line6
->
urb_listen
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
ret
=
usb_set_interface
(
usbdev
,
interface_number
,
properties
->
altsetting
);
if
(
ret
<
0
)
{
dev_err
(
&
interface
->
dev
,
"set_interface failed
\n
"
);
goto
error
;
}
if
(
line6
->
urb_listen
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
err_destruct
;
}
line6_get_interval
(
line6
);
ret
=
line6_start_listen
(
line6
);
if
(
ret
<
0
)
{
dev_err
(
&
interface
->
dev
,
"%s: usb_submit_urb failed
\n
"
,
__func__
);
goto
err_destruct
;
}
if
(
properties
->
capabilities
&
LINE6_CAP_CONTROL
)
{
ret
=
line6_init_cap_control
(
line6
);
if
(
ret
<
0
)
goto
error
;
}
/* initialize device data based on device: */
ret
=
private_init
(
interface
,
line6
);
ret
=
private_init
(
line6
,
id
);
if
(
ret
<
0
)
goto
err
_destruct
;
goto
err
or
;
/* creation of additional special files should go here */
dev_info
(
&
interface
->
dev
,
"Line 6 %s now attached
\n
"
,
line6
->
properties
->
name
);
properties
->
name
);
return
0
;
err_destruct:
error:
if
(
line6
->
disconnect
)
line6
->
disconnect
(
line6
);
snd_card_free
(
card
);
err_put:
return
ret
;
}
EXPORT_SYMBOL_GPL
(
line6_probe
);
...
...
@@ -579,32 +570,23 @@ EXPORT_SYMBOL_GPL(line6_probe);
*/
void
line6_disconnect
(
struct
usb_interface
*
interface
)
{
struct
usb_line6
*
line6
;
struct
usb_device
*
usbdev
;
int
interface_number
;
struct
usb_line6
*
line6
=
usb_get_intfdata
(
interface
);
struct
usb_device
*
usbdev
=
interface_to_usbdev
(
interface
);
if
(
interface
==
NULL
)
return
;
usbdev
=
interface_to_usbdev
(
interface
);
if
(
usbdev
==
NULL
)
if
(
!
line6
)
return
;
interface_number
=
interface
->
cur_altsetting
->
desc
.
bInterfaceNumber
;
line6
=
usb_get_intfdata
(
interface
);
if
(
!
line6
)
if
(
WARN_ON
(
usbdev
!=
line6
->
usbdev
))
return
;
if
(
line6
->
urb_listen
!=
NULL
)
line6_stop_listen
(
line6
);
if
(
usbdev
!=
line6
->
usbdev
)
dev_err
(
line6
->
ifcdev
,
"driver bug: inconsistent usb device
\n
"
);
snd_card_disconnect
(
line6
->
card
);
if
(
line6
->
line6pcm
)
line6_pcm_disconnect
(
line6
->
line6pcm
);
if
(
line6
->
disconnect
)
line6
->
disconnect
(
interface
);
line6
->
disconnect
(
line6
);
dev_info
(
&
interface
->
dev
,
"Line 6 %s now disconnected
\n
"
,
line6
->
properties
->
name
);
...
...
sound/usb/line6/driver.h
浏览文件 @
5e0ddd07
...
...
@@ -157,13 +157,11 @@ struct usb_line6 {
int
message_length
;
void
(
*
process_message
)(
struct
usb_line6
*
);
void
(
*
disconnect
)(
struct
usb_
interface
*
);
void
(
*
disconnect
)(
struct
usb_
line6
*
line6
);
};
extern
char
*
line6_alloc_sysex_buffer
(
struct
usb_line6
*
line6
,
int
code1
,
int
code2
,
int
size
);
extern
ssize_t
line6_nop_read
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
);
extern
int
line6_read_data
(
struct
usb_line6
*
line6
,
int
address
,
void
*
data
,
size_t
datalen
);
extern
int
line6_read_serial_number
(
struct
usb_line6
*
line6
,
...
...
@@ -182,9 +180,11 @@ extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
size_t
datalen
);
int
line6_probe
(
struct
usb_interface
*
interface
,
struct
usb_line6
*
line6
,
const
struct
usb_device_id
*
id
,
const
struct
line6_properties
*
properties
,
int
(
*
private_init
)(
struct
usb_interface
*
,
struct
usb_line6
*
));
int
(
*
private_init
)(
struct
usb_line6
*
,
const
struct
usb_device_id
*
id
),
size_t
data_size
);
void
line6_disconnect
(
struct
usb_interface
*
interface
);
#ifdef CONFIG_PM
...
...
sound/usb/line6/midi.c
浏览文件 @
5e0ddd07
...
...
@@ -45,12 +45,9 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
line6_rawmidi_substream_midi
(
substream
)
->
line6
;
struct
snd_line6_midi
*
line6midi
=
line6
->
line6midi
;
struct
midi_buffer
*
mb
=
&
line6midi
->
midibuf_out
;
unsigned
long
flags
;
unsigned
char
chunk
[
LINE6_FALLBACK_MAXPACKETSIZE
];
int
req
,
done
;
spin_lock_irqsave
(
&
line6
->
line6midi
->
midi_transmit_lock
,
flags
);
for
(;;)
{
req
=
min
(
line6_midibuf_bytes_free
(
mb
),
line6
->
max_packet_size
);
done
=
snd_rawmidi_transmit_peek
(
substream
,
chunk
,
req
);
...
...
@@ -71,8 +68,6 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
send_midi_async
(
line6
,
chunk
,
done
);
}
spin_unlock_irqrestore
(
&
line6
->
line6midi
->
midi_transmit_lock
,
flags
);
}
/*
...
...
@@ -92,7 +87,7 @@ static void midi_sent(struct urb *urb)
if
(
status
==
-
ESHUTDOWN
)
return
;
spin_lock_irqsave
(
&
line6
->
line6midi
->
send_urb_
lock
,
flags
);
spin_lock_irqsave
(
&
line6
->
line6midi
->
lock
,
flags
);
num
=
--
line6
->
line6midi
->
num_active_send_urbs
;
if
(
num
==
0
)
{
...
...
@@ -103,12 +98,12 @@ static void midi_sent(struct urb *urb)
if
(
num
==
0
)
wake_up
(
&
line6
->
line6midi
->
send_wait
);
spin_unlock_irqrestore
(
&
line6
->
line6midi
->
send_urb_
lock
,
flags
);
spin_unlock_irqrestore
(
&
line6
->
line6midi
->
lock
,
flags
);
}
/*
Send an asynchronous MIDI message.
Assumes that line6->line6midi->
send_urb_
lock is held
Assumes that line6->line6midi->lock is held
(i.e., this function is serialized).
*/
static
int
send_midi_async
(
struct
usb_line6
*
line6
,
unsigned
char
*
data
,
...
...
@@ -166,12 +161,12 @@ static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
line6_rawmidi_substream_midi
(
substream
)
->
line6
;
line6
->
line6midi
->
substream_transmit
=
substream
;
spin_lock_irqsave
(
&
line6
->
line6midi
->
send_urb_
lock
,
flags
);
spin_lock_irqsave
(
&
line6
->
line6midi
->
lock
,
flags
);
if
(
line6
->
line6midi
->
num_active_send_urbs
==
0
)
line6_midi_transmit
(
substream
);
spin_unlock_irqrestore
(
&
line6
->
line6midi
->
send_urb_
lock
,
flags
);
spin_unlock_irqrestore
(
&
line6
->
line6midi
->
lock
,
flags
);
}
static
void
line6_midi_output_drain
(
struct
snd_rawmidi_substream
*
substream
)
...
...
@@ -281,8 +276,7 @@ int line6_init_midi(struct usb_line6 *line6)
rmidi
->
private_free
=
snd_line6_midi_free
;
init_waitqueue_head
(
&
line6midi
->
send_wait
);
spin_lock_init
(
&
line6midi
->
send_urb_lock
);
spin_lock_init
(
&
line6midi
->
midi_transmit_lock
);
spin_lock_init
(
&
line6midi
->
lock
);
line6midi
->
line6
=
line6
;
err
=
line6_midibuf_init
(
&
line6midi
->
midibuf_in
,
MIDI_BUFFER_SIZE
,
0
);
...
...
sound/usb/line6/midi.h
浏览文件 @
5e0ddd07
...
...
@@ -39,15 +39,10 @@ struct snd_line6_midi {
*/
int
num_active_send_urbs
;
/**
Spin lock to protect updates of send_urb.
*/
spinlock_t
send_urb_lock
;
/**
Spin lock to protect MIDI buffer handling.
*/
spinlock_t
midi_transmit_
lock
;
spinlock_t
lock
;
/**
Wait queue for MIDI transmission.
...
...
sound/usb/line6/pcm.c
浏览文件 @
5e0ddd07
...
...
@@ -45,15 +45,22 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
{
struct
snd_line6_pcm
*
line6pcm
=
snd_kcontrol_chip
(
kcontrol
);
int
value
=
ucontrol
->
value
.
integer
.
value
[
0
];
int
err
;
if
(
line6pcm
->
impulse_volume
==
value
)
return
0
;
line6pcm
->
impulse_volume
=
value
;
if
(
value
>
0
)
line6_pcm_acquire
(
line6pcm
,
LINE6_BITS_PCM_IMPULSE
);
else
line6_pcm_release
(
line6pcm
,
LINE6_BITS_PCM_IMPULSE
);
if
(
value
>
0
)
{
err
=
line6_pcm_acquire
(
line6pcm
,
LINE6_STREAM_IMPULSE
);
if
(
err
<
0
)
{
line6pcm
->
impulse_volume
=
0
;
line6_pcm_release
(
line6pcm
,
LINE6_STREAM_IMPULSE
);
return
err
;
}
}
else
{
line6_pcm_release
(
line6pcm
,
LINE6_STREAM_IMPULSE
);
}
return
1
;
}
...
...
@@ -90,180 +97,277 @@ static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
return
1
;
}
static
bool
test_flags
(
unsigned
long
flags0
,
unsigned
long
flags1
,
unsigned
long
mask
)
{
return
((
flags0
&
mask
)
==
0
)
&&
((
flags1
&
mask
)
!=
0
);
}
int
line6_pcm_acquire
(
struct
snd_line6_pcm
*
line6pcm
,
int
channels
)
/*
Unlink all currently active URBs.
*/
static
void
line6_unlink_audio_urbs
(
struct
snd_line6_pcm
*
line6pcm
,
struct
line6_pcm_stream
*
pcms
)
{
unsigned
long
flags_old
,
flags_new
,
flags_final
;
int
err
;
do
{
flags_old
=
ACCESS_ONCE
(
line6pcm
->
flags
);
flags_new
=
flags_old
|
channels
;
}
while
(
cmpxchg
(
&
line6pcm
->
flags
,
flags_old
,
flags_new
)
!=
flags_old
);
flags_final
=
flags_old
;
line6pcm
->
prev_fbuf
=
NULL
;
if
(
test_flags
(
flags_old
,
flags_new
,
LINE6_BITS_CAPTURE_BUFFER
))
{
/* Invoked multiple times in a row so allocate once only */
if
(
!
line6pcm
->
buffer_in
)
{
line6pcm
->
buffer_in
=
kmalloc
(
LINE6_ISO_BUFFERS
*
LINE6_ISO_PACKETS
*
line6pcm
->
max_packet_size
,
GFP_KERNEL
);
if
(
!
line6pcm
->
buffer_in
)
{
err
=
-
ENOMEM
;
goto
pcm_acquire_error
;
}
flags_final
|=
channels
&
LINE6_BITS_CAPTURE_BUFFER
;
}
}
int
i
;
if
(
test_flags
(
flags_old
,
flags_new
,
LINE6_BITS_CAPTURE_STREAM
))
{
/*
Waiting for completion of active URBs in the stop handler is
a bug, we therefore report an error if capturing is restarted
too soon.
*/
if
(
line6pcm
->
active_urb_in
|
line6pcm
->
unlink_urb_in
)
{
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"Device not yet ready
\n
"
);
return
-
EBUSY
;
for
(
i
=
0
;
i
<
LINE6_ISO_BUFFERS
;
i
++
)
{
if
(
test_bit
(
i
,
&
pcms
->
active_urbs
))
{
if
(
!
test_and_set_bit
(
i
,
&
pcms
->
unlink_urbs
))
usb_unlink_urb
(
pcms
->
urbs
[
i
]);
}
line6pcm
->
count_in
=
0
;
line6pcm
->
prev_fsize
=
0
;
err
=
line6_submit_audio_in_all_urbs
(
line6pcm
);
if
(
err
<
0
)
goto
pcm_acquire_error
;
flags_final
|=
channels
&
LINE6_BITS_CAPTURE_STREAM
;
}
}
if
(
test_flags
(
flags_old
,
flags_new
,
LINE6_BITS_PLAYBACK_BUFFER
))
{
/* Invoked multiple times in a row so allocate once only */
if
(
!
line6pcm
->
buffer_out
)
{
line6pcm
->
buffer_out
=
kmalloc
(
LINE6_ISO_BUFFERS
*
LINE6_ISO_PACKETS
*
line6pcm
->
max_packet_size
,
GFP_KERNEL
);
if
(
!
line6pcm
->
buffer_out
)
{
err
=
-
ENOMEM
;
goto
pcm_acquire_error
;
}
flags_final
|=
channels
&
LINE6_BITS_PLAYBACK_BUFFER
;
}
}
/*
Wait until unlinking of all currently active URBs has been finished.
*/
static
void
line6_wait_clear_audio_urbs
(
struct
snd_line6_pcm
*
line6pcm
,
struct
line6_pcm_stream
*
pcms
)
{
int
timeout
=
HZ
;
int
i
;
int
alive
;
if
(
test_flags
(
flags_old
,
flags_new
,
LINE6_BITS_PLAYBACK_STREAM
))
{
/*
See comment above regarding PCM restart.
*/
if
(
line6pcm
->
active_urb_out
|
line6pcm
->
unlink_urb_out
)
{
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"Device not yet ready
\n
"
);
return
-
EBUSY
;
do
{
alive
=
0
;
for
(
i
=
0
;
i
<
LINE6_ISO_BUFFERS
;
i
++
)
{
if
(
test_bit
(
i
,
&
pcms
->
active_urbs
))
alive
++
;
}
if
(
!
alive
)
break
;
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
1
);
}
while
(
--
timeout
>
0
);
if
(
alive
)
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"timeout: still %d active urbs..
\n
"
,
alive
);
}
line6pcm
->
count_out
=
0
;
err
=
line6_submit_audio_out_all_urbs
(
line6pcm
);
if
(
err
<
0
)
goto
pcm_acquire_error
;
static
inline
struct
line6_pcm_stream
*
get_stream
(
struct
snd_line6_pcm
*
line6pcm
,
int
direction
)
{
return
(
direction
==
SNDRV_PCM_STREAM_PLAYBACK
)
?
&
line6pcm
->
out
:
&
line6pcm
->
in
;
}
flags_final
|=
channels
&
LINE6_BITS_PLAYBACK_STREAM
;
/* allocate a buffer if not opened yet;
* call this in line6pcm.state_change mutex
*/
static
int
line6_buffer_acquire
(
struct
snd_line6_pcm
*
line6pcm
,
struct
line6_pcm_stream
*
pstr
,
int
type
)
{
/* Invoked multiple times in a row so allocate once only */
if
(
!
test_and_set_bit
(
type
,
&
pstr
->
opened
)
&&
!
pstr
->
buffer
)
{
pstr
->
buffer
=
kmalloc
(
LINE6_ISO_BUFFERS
*
LINE6_ISO_PACKETS
*
line6pcm
->
max_packet_size
,
GFP_KERNEL
);
if
(
!
pstr
->
buffer
)
return
-
ENOMEM
;
}
return
0
;
pcm_acquire_error:
/*
If not all requested resources/streams could be obtained, release
those which were successfully obtained (if any).
*/
line6_pcm_release
(
line6pcm
,
flags_final
&
channels
);
return
err
;
}
EXPORT_SYMBOL_GPL
(
line6_pcm_acquire
);
int
line6_pcm_release
(
struct
snd_line6_pcm
*
line6pcm
,
int
channels
)
/* free a buffer if all streams are closed;
* call this in line6pcm.state_change mutex
*/
static
void
line6_buffer_release
(
struct
snd_line6_pcm
*
line6pcm
,
struct
line6_pcm_stream
*
pstr
,
int
type
)
{
unsigned
long
flags_old
,
flags_new
;
do
{
flags_old
=
ACCESS_ONCE
(
line6pcm
->
flags
);
flags_new
=
flags_old
&
~
channels
;
}
while
(
cmpxchg
(
&
line6pcm
->
flags
,
flags_old
,
flags_new
)
!=
flags_old
);
if
(
test_flags
(
flags_new
,
flags_old
,
LINE6_BITS_CAPTURE_STREAM
))
line6_unlink_audio_in_urbs
(
line6pcm
);
if
(
test_flags
(
flags_new
,
flags_old
,
LINE6_BITS_CAPTURE_BUFFER
))
{
line6_wait_clear_audio_in_urbs
(
line6pcm
);
line6_free_capture_buffer
(
line6pcm
);
clear_bit
(
type
,
&
pstr
->
opened
);
if
(
!
pstr
->
opened
)
{
line6_wait_clear_audio_urbs
(
line6pcm
,
pstr
);
kfree
(
pstr
->
buffer
);
pstr
->
buffer
=
NULL
;
}
}
if
(
test_flags
(
flags_new
,
flags_old
,
LINE6_BITS_PLAYBACK_STREAM
))
line6_unlink_audio_out_urbs
(
line6pcm
);
/* start a PCM stream */
static
int
line6_stream_start
(
struct
snd_line6_pcm
*
line6pcm
,
int
direction
,
int
type
)
{
unsigned
long
flags
;
struct
line6_pcm_stream
*
pstr
=
get_stream
(
line6pcm
,
direction
);
int
ret
=
0
;
spin_lock_irqsave
(
&
pstr
->
lock
,
flags
);
if
(
!
test_and_set_bit
(
type
,
&
pstr
->
running
))
{
if
(
pstr
->
active_urbs
||
pstr
->
unlink_urbs
)
{
ret
=
-
EBUSY
;
goto
error
;
}
if
(
test_flags
(
flags_new
,
flags_old
,
LINE6_BITS_PLAYBACK_BUFFER
))
{
line6_wait_clear_audio_out_urbs
(
line6pcm
);
line6_free_playback_buffer
(
line6pcm
);
pstr
->
count
=
0
;
/* Submit all currently available URBs */
if
(
direction
==
SNDRV_PCM_STREAM_PLAYBACK
)
ret
=
line6_submit_audio_out_all_urbs
(
line6pcm
);
else
ret
=
line6_submit_audio_in_all_urbs
(
line6pcm
);
}
error:
if
(
ret
<
0
)
clear_bit
(
type
,
&
pstr
->
running
);
spin_unlock_irqrestore
(
&
pstr
->
lock
,
flags
);
return
ret
;
}
return
0
;
/* stop a PCM stream; this doesn't sync with the unlinked URBs */
static
void
line6_stream_stop
(
struct
snd_line6_pcm
*
line6pcm
,
int
direction
,
int
type
)
{
unsigned
long
flags
;
struct
line6_pcm_stream
*
pstr
=
get_stream
(
line6pcm
,
direction
);
spin_lock_irqsave
(
&
pstr
->
lock
,
flags
);
clear_bit
(
type
,
&
pstr
->
running
);
if
(
!
pstr
->
running
)
{
line6_unlink_audio_urbs
(
line6pcm
,
pstr
);
if
(
direction
==
SNDRV_PCM_STREAM_CAPTURE
)
{
line6pcm
->
prev_fbuf
=
NULL
;
line6pcm
->
prev_fsize
=
0
;
}
}
spin_unlock_irqrestore
(
&
pstr
->
lock
,
flags
);
}
EXPORT_SYMBOL_GPL
(
line6_pcm_release
);
/* trigger callback */
/*
common PCM
trigger callback */
int
snd_line6_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
struct
snd_pcm_substream
*
s
;
int
err
;
spin_lock
(
&
line6pcm
->
lock_trigger
);
clear_bit
(
LINE6_INDEX_PREPARED
,
&
line6pcm
->
flags
);
clear_bit
(
LINE6_FLAG_PREPARED
,
&
line6pcm
->
flags
);
snd_pcm_group_for_each_entry
(
s
,
substream
)
{
if
(
s
->
pcm
->
card
!=
substream
->
pcm
->
card
)
continue
;
switch
(
s
->
stream
)
{
case
SNDRV_PCM_STREAM_PLAYBACK
:
err
=
snd_line6_playback_trigger
(
line6pcm
,
cmd
);
if
(
err
<
0
)
{
spin_unlock
(
&
line6pcm
->
lock_trigger
);
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
case
SNDRV_PCM_TRIGGER_RESUME
:
err
=
line6_stream_start
(
line6pcm
,
s
->
stream
,
LINE6_STREAM_PCM
);
if
(
err
<
0
)
return
err
;
}
break
;
case
SNDRV_PCM_STREAM_CAPTURE
:
err
=
snd_line6_capture_trigger
(
line6pcm
,
cmd
);
case
SNDRV_PCM_TRIGGER_STOP
:
case
SNDRV_PCM_TRIGGER_SUSPEND
:
line6_stream_stop
(
line6pcm
,
s
->
stream
,
LINE6_STREAM_PCM
);
break
;
if
(
err
<
0
)
{
spin_unlock
(
&
line6pcm
->
lock_trigger
);
return
err
;
}
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
if
(
s
->
stream
!=
SNDRV_PCM_STREAM_PLAYBACK
)
return
-
EINVAL
;
set_bit
(
LINE6_FLAG_PAUSE_PLAYBACK
,
&
line6pcm
->
flags
);
break
;
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
if
(
s
->
stream
!=
SNDRV_PCM_STREAM_PLAYBACK
)
return
-
EINVAL
;
clear_bit
(
LINE6_FLAG_PAUSE_PLAYBACK
,
&
line6pcm
->
flags
);
break
;
default:
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"Unknown stream direction %d
\n
"
,
s
->
stream
);
return
-
EINVAL
;
}
}
spin_unlock
(
&
line6pcm
->
lock_trigger
);
return
0
;
}
/* common PCM pointer callback */
snd_pcm_uframes_t
snd_line6_pointer
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
struct
line6_pcm_stream
*
pstr
=
get_stream
(
line6pcm
,
substream
->
stream
);
return
pstr
->
pos_done
;
}
/* Acquire and start duplex streams:
* type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
*/
int
line6_pcm_acquire
(
struct
snd_line6_pcm
*
line6pcm
,
int
type
)
{
struct
line6_pcm_stream
*
pstr
;
int
ret
=
0
,
dir
;
mutex_lock
(
&
line6pcm
->
state_mutex
);
for
(
dir
=
0
;
dir
<
2
;
dir
++
)
{
pstr
=
get_stream
(
line6pcm
,
dir
);
ret
=
line6_buffer_acquire
(
line6pcm
,
pstr
,
type
);
if
(
ret
<
0
)
goto
error
;
if
(
!
pstr
->
running
)
line6_wait_clear_audio_urbs
(
line6pcm
,
pstr
);
}
for
(
dir
=
0
;
dir
<
2
;
dir
++
)
{
ret
=
line6_stream_start
(
line6pcm
,
dir
,
type
);
if
(
ret
<
0
)
goto
error
;
}
error:
mutex_unlock
(
&
line6pcm
->
state_mutex
);
if
(
ret
<
0
)
line6_pcm_release
(
line6pcm
,
type
);
return
ret
;
}
EXPORT_SYMBOL_GPL
(
line6_pcm_acquire
);
/* Stop and release duplex streams */
void
line6_pcm_release
(
struct
snd_line6_pcm
*
line6pcm
,
int
type
)
{
struct
line6_pcm_stream
*
pstr
;
int
dir
;
mutex_lock
(
&
line6pcm
->
state_mutex
);
for
(
dir
=
0
;
dir
<
2
;
dir
++
)
line6_stream_stop
(
line6pcm
,
dir
,
type
);
for
(
dir
=
0
;
dir
<
2
;
dir
++
)
{
pstr
=
get_stream
(
line6pcm
,
dir
);
line6_buffer_release
(
line6pcm
,
pstr
,
type
);
}
mutex_unlock
(
&
line6pcm
->
state_mutex
);
}
EXPORT_SYMBOL_GPL
(
line6_pcm_release
);
/* common PCM hw_params callback */
int
snd_line6_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
hw_params
)
{
int
ret
;
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
struct
line6_pcm_stream
*
pstr
=
get_stream
(
line6pcm
,
substream
->
stream
);
mutex_lock
(
&
line6pcm
->
state_mutex
);
ret
=
line6_buffer_acquire
(
line6pcm
,
pstr
,
LINE6_STREAM_PCM
);
if
(
ret
<
0
)
goto
error
;
ret
=
snd_pcm_lib_malloc_pages
(
substream
,
params_buffer_bytes
(
hw_params
));
if
(
ret
<
0
)
{
line6_buffer_release
(
line6pcm
,
pstr
,
LINE6_STREAM_PCM
);
goto
error
;
}
pstr
->
period
=
params_period_bytes
(
hw_params
);
error:
mutex_unlock
(
&
line6pcm
->
state_mutex
);
return
ret
;
}
/* common PCM hw_free callback */
int
snd_line6_hw_free
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
struct
line6_pcm_stream
*
pstr
=
get_stream
(
line6pcm
,
substream
->
stream
);
mutex_lock
(
&
line6pcm
->
state_mutex
);
line6_buffer_release
(
line6pcm
,
pstr
,
LINE6_STREAM_PCM
);
mutex_unlock
(
&
line6pcm
->
state_mutex
);
return
snd_pcm_lib_free_pages
(
substream
);
}
/* control info callback */
static
int
snd_line6_control_playback_info
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_info
*
uinfo
)
...
...
@@ -282,7 +386,7 @@ static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
int
i
;
struct
snd_line6_pcm
*
line6pcm
=
snd_kcontrol_chip
(
kcontrol
);
for
(
i
=
2
;
i
--
;
)
for
(
i
=
0
;
i
<
2
;
i
++
)
ucontrol
->
value
.
integer
.
value
[
i
]
=
line6pcm
->
volume_playback
[
i
];
return
0
;
...
...
@@ -295,7 +399,7 @@ static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
int
i
,
changed
=
0
;
struct
snd_line6_pcm
*
line6pcm
=
snd_kcontrol_chip
(
kcontrol
);
for
(
i
=
2
;
i
--
;
)
for
(
i
=
0
;
i
<
2
;
i
++
)
if
(
line6pcm
->
volume_playback
[
i
]
!=
ucontrol
->
value
.
integer
.
value
[
i
])
{
line6pcm
->
volume_playback
[
i
]
=
...
...
@@ -334,21 +438,24 @@ static struct snd_kcontrol_new line6_controls[] = {
/*
Cleanup the PCM device.
*/
static
void
line6_cleanup_pcm
(
struct
snd_pcm
*
pcm
)
static
void
cleanup_urbs
(
struct
line6_pcm_stream
*
pcms
)
{
int
i
;
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_chip
(
pcm
);
for
(
i
=
LINE6_ISO_BUFFERS
;
i
--
;)
{
if
(
line6pcm
->
urb_audio_out
[
i
])
{
usb_kill_urb
(
line6pcm
->
urb_audio_out
[
i
]);
usb_free_urb
(
line6pcm
->
urb_audio_out
[
i
]);
}
if
(
line6pcm
->
urb_audio_in
[
i
])
{
usb_kill_urb
(
line6pcm
->
urb_audio_in
[
i
]);
usb_free_urb
(
line6pcm
->
urb_audio_in
[
i
]);
for
(
i
=
0
;
i
<
LINE6_ISO_BUFFERS
;
i
++
)
{
if
(
pcms
->
urbs
[
i
])
{
usb_kill_urb
(
pcms
->
urbs
[
i
]);
usb_free_urb
(
pcms
->
urbs
[
i
]);
}
}
}
static
void
line6_cleanup_pcm
(
struct
snd_pcm
*
pcm
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_chip
(
pcm
);
cleanup_urbs
(
&
line6pcm
->
out
);
cleanup_urbs
(
&
line6pcm
->
in
);
kfree
(
line6pcm
);
}
...
...
@@ -383,8 +490,10 @@ static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
*/
void
line6_pcm_disconnect
(
struct
snd_line6_pcm
*
line6pcm
)
{
line6_unlink_wait_clear_audio_out_urbs
(
line6pcm
);
line6_unlink_wait_clear_audio_in_urbs
(
line6pcm
);
line6_unlink_audio_urbs
(
line6pcm
,
&
line6pcm
->
out
);
line6_unlink_audio_urbs
(
line6pcm
,
&
line6pcm
->
in
);
line6_wait_clear_audio_urbs
(
line6pcm
,
&
line6pcm
->
out
);
line6_wait_clear_audio_urbs
(
line6pcm
,
&
line6pcm
->
in
);
}
/*
...
...
@@ -411,6 +520,7 @@ int line6_init_pcm(struct usb_line6 *line6,
if
(
!
line6pcm
)
return
-
ENOMEM
;
mutex_init
(
&
line6pcm
->
state_mutex
);
line6pcm
->
pcm
=
pcm
;
line6pcm
->
properties
=
properties
;
line6pcm
->
volume_playback
[
0
]
=
line6pcm
->
volume_playback
[
1
]
=
255
;
...
...
@@ -424,9 +534,8 @@ int line6_init_pcm(struct usb_line6 *line6,
usb_maxpacket
(
line6
->
usbdev
,
usb_sndisocpipe
(
line6
->
usbdev
,
ep_write
),
1
));
spin_lock_init
(
&
line6pcm
->
lock_audio_out
);
spin_lock_init
(
&
line6pcm
->
lock_audio_in
);
spin_lock_init
(
&
line6pcm
->
lock_trigger
);
spin_lock_init
(
&
line6pcm
->
out
.
lock
);
spin_lock_init
(
&
line6pcm
->
in
.
lock
);
line6pcm
->
impulse_period
=
LINE6_IMPULSE_DEFAULT_PERIOD
;
line6
->
line6pcm
=
line6pcm
;
...
...
@@ -458,30 +567,22 @@ EXPORT_SYMBOL_GPL(line6_init_pcm);
int
snd_line6_prepare
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
switch
(
substream
->
stream
)
{
case
SNDRV_PCM_STREAM_PLAYBACK
:
if
((
line6pcm
->
flags
&
LINE6_BITS_PLAYBACK_STREAM
)
==
0
)
line6_unlink_wait_clear_audio_out_urbs
(
line6pcm
);
break
;
case
SNDRV_PCM_STREAM_CAPTURE
:
if
((
line6pcm
->
flags
&
LINE6_BITS_CAPTURE_STREAM
)
==
0
)
line6_unlink_wait_clear_audio_in_urbs
(
line6pcm
);
break
;
}
if
(
!
test_and_set_bit
(
LINE6_INDEX_PREPARED
,
&
line6pcm
->
flags
))
{
line6pcm
->
count_out
=
0
;
line6pcm
->
pos_out
=
0
;
line6pcm
->
pos_out_done
=
0
;
line6pcm
->
bytes_out
=
0
;
line6pcm
->
count_in
=
0
;
line6pcm
->
pos_in_done
=
0
;
line6pcm
->
bytes_in
=
0
;
struct
line6_pcm_stream
*
pstr
=
get_stream
(
line6pcm
,
substream
->
stream
);
mutex_lock
(
&
line6pcm
->
state_mutex
);
if
(
!
pstr
->
running
)
line6_wait_clear_audio_urbs
(
line6pcm
,
pstr
);
if
(
!
test_and_set_bit
(
LINE6_FLAG_PREPARED
,
&
line6pcm
->
flags
))
{
line6pcm
->
out
.
count
=
0
;
line6pcm
->
out
.
pos
=
0
;
line6pcm
->
out
.
pos_done
=
0
;
line6pcm
->
out
.
bytes
=
0
;
line6pcm
->
in
.
count
=
0
;
line6pcm
->
in
.
pos_done
=
0
;
line6pcm
->
in
.
bytes
=
0
;
}
mutex_unlock
(
&
line6pcm
->
state_mutex
);
return
0
;
}
sound/usb/line6/pcm.h
浏览文件 @
5e0ddd07
...
...
@@ -54,109 +54,33 @@
However, from the device's point of view, there is just a single
capture and playback stream, which must be shared between these
subsystems. It is therefore necessary to maintain the state of the
subsystems with respect to PCM usage. We define several constants of
the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
following meanings:
*) <subsystem> is one of
-) ALSA: PCM playback and capture via ALSA
-) MONITOR: software monitoring
-) IMPULSE: optional impulse response measurement
*) <direction> is one of
-) PLAYBACK: audio output (from host to device)
-) CAPTURE: audio input (from device to host)
*) <resource> is one of
-) BUFFER: buffer required by PCM data stream
-) STREAM: actual PCM data stream
The subsystems call line6_pcm_acquire() to acquire the (shared)
resources needed for a particular operation (e.g., allocate the buffer
for ALSA playback or start the capture stream for software monitoring).
When a resource is no longer needed, it is released by calling
line6_pcm_release(). Buffer allocation and stream startup are handled
separately to allow the ALSA kernel driver to perform them at
appropriate places (since the callback which starts a PCM stream is not
allowed to sleep).
subsystems with respect to PCM usage.
We define two bit flags, "opened" and "running", for each playback
or capture stream. Both can contain the bit flag corresponding to
LINE6_STREAM_* type,
LINE6_STREAM_PCM = ALSA PCM playback or capture
LINE6_STREAM_MONITOR = software monitoring
IMPULSE = optional impulse response measurement
The opened flag indicates whether the buffer is allocated while
the running flag indicates whether the stream is running.
For monitor or impulse operations, the driver needs to call
snd_line6_duplex_acquire() or snd_line6_duplex_release() with the
appropriate LINE6_STREAM_* flag.
*/
/* stream types */
enum
{
/* individual bit indices: */
LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER
,
LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM
,
LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER
,
LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM
,
LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER
,
LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM
,
LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER
,
LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM
,
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER
,
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM
,
LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER
,
LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM
,
LINE6_INDEX_PAUSE_PLAYBACK
,
LINE6_INDEX_PREPARED
,
#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
/* individual bit masks: */
LINE6_BIT
(
PCM_ALSA_PLAYBACK_BUFFER
),
LINE6_BIT
(
PCM_ALSA_PLAYBACK_STREAM
),
LINE6_BIT
(
PCM_ALSA_CAPTURE_BUFFER
),
LINE6_BIT
(
PCM_ALSA_CAPTURE_STREAM
),
LINE6_BIT
(
PCM_MONITOR_PLAYBACK_BUFFER
),
LINE6_BIT
(
PCM_MONITOR_PLAYBACK_STREAM
),
LINE6_BIT
(
PCM_MONITOR_CAPTURE_BUFFER
),
LINE6_BIT
(
PCM_MONITOR_CAPTURE_STREAM
),
LINE6_BIT
(
PCM_IMPULSE_PLAYBACK_BUFFER
),
LINE6_BIT
(
PCM_IMPULSE_PLAYBACK_STREAM
),
LINE6_BIT
(
PCM_IMPULSE_CAPTURE_BUFFER
),
LINE6_BIT
(
PCM_IMPULSE_CAPTURE_STREAM
),
LINE6_BIT
(
PAUSE_PLAYBACK
),
LINE6_BIT
(
PREPARED
),
/* combined bit masks (by operation): */
LINE6_BITS_PCM_ALSA_BUFFER
=
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER
|
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER
,
LINE6_BITS_PCM_ALSA_STREAM
=
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM
|
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM
,
LINE6_BITS_PCM_MONITOR
=
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER
|
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM
|
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER
|
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM
,
LINE6_BITS_PCM_IMPULSE
=
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER
|
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM
|
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER
|
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM
,
/* combined bit masks (by direction): */
LINE6_BITS_PLAYBACK_BUFFER
=
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER
|
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER
|
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER
,
LINE6_BITS_PLAYBACK_STREAM
=
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM
|
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM
|
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM
,
LINE6_BITS_CAPTURE_BUFFER
=
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER
|
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER
|
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER
,
LINE6_BITS_CAPTURE_STREAM
=
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM
|
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM
|
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM
,
LINE6_BITS_STREAM
=
LINE6_BITS_PLAYBACK_STREAM
|
LINE6_BITS_CAPTURE_STREAM
LINE6_STREAM_PCM
,
LINE6_STREAM_MONITOR
,
LINE6_STREAM_IMPULSE
,
};
/* misc bit flags for PCM operation */
enum
{
LINE6_FLAG_PAUSE_PLAYBACK
,
LINE6_FLAG_PREPARED
,
};
struct
line6_pcm_properties
{
...
...
@@ -165,153 +89,93 @@ struct line6_pcm_properties {
int
bytes_per_frame
;
};
struct
snd_line6_pcm
{
/**
Pointer back to the Line 6 driver data structure.
*/
struct
usb_line6
*
line6
;
struct
line6_pcm_stream
{
/* allocated URBs */
struct
urb
*
urbs
[
LINE6_ISO_BUFFERS
];
/**
Properties.
*/
struct
line6_pcm_properties
*
properties
;
/* Temporary buffer;
* Since the packet size is not known in advance, this buffer is
* large enough to store maximum size packets.
*/
unsigned
char
*
buffer
;
/**
ALSA pcm stream
*/
struct
snd_pcm
*
pcm
;
/* Free frame position in the buffer. */
snd_pcm_uframes_t
pos
;
/*
*
URBs for audio playback
.
*/
struct
urb
*
urb_audio_out
[
LINE6_ISO_BUFFERS
]
;
/*
Count processed bytes;
* This is modulo period size (to determine when a period is finished)
.
*/
unsigned
bytes
;
/**
URBs for audio capture.
*/
struct
urb
*
urb_audio_in
[
LINE6_ISO_BUFFERS
];
/* Counter to create desired sample rate */
unsigned
count
;
/**
Temporary buffer for playback.
Since the packet size is not known in advance, this buffer is
large enough to store maximum size packets.
*/
unsigned
char
*
buffer_out
;
/* period size in bytes */
unsigned
period
;
/**
Temporary buffer for capture.
Since the packet size is not known in advance, this buffer is
large enough to store maximum size packets.
*/
unsigned
char
*
buffer_in
;
/* Processed frame position in the buffer;
* The contents of the ring buffer have been consumed by the USB
* subsystem (i.e., sent to the USB device) up to this position.
*/
snd_pcm_uframes_t
pos_done
;
/**
Previously captured frame (for software monitoring).
*/
unsigned
char
*
prev_fbuf
;
/* Bit mask of active URBs */
unsigned
long
active_urbs
;
/**
Size of previously captured frame (for software monitoring).
*/
int
prev_fsize
;
/* Bit mask of URBs currently being unlinked */
unsigned
long
unlink_urbs
;
/**
Free frame position in the playback buffer.
*/
snd_pcm_uframes_t
pos_out
;
/* Spin lock to protect updates of the buffer positions (not contents)
*/
spinlock_t
lock
;
/**
Count processed bytes for playback.
This is modulo period size (to determine when a period is
finished).
*/
unsigned
bytes_out
;
/* Bit flags for operational stream types */
unsigned
long
opened
;
/**
Counter to create desired playback sample rate.
*/
unsigned
count_out
;
/* Bit flags for running stream types */
unsigned
long
running
;
/**
Playback period size in bytes
*/
unsigned
period_out
;
int
last_frame
;
};
struct
snd_line6_pcm
{
/**
Processed frame position in the playback buffer.
The contents of the output ring buffer have been consumed by
the USB subsystem (i.e., sent to the USB device) up to this
position.
Pointer back to the Line 6 driver data structure.
*/
s
nd_pcm_uframes_t
pos_out_done
;
s
truct
usb_line6
*
line6
;
/**
Count processed bytes for capture.
This is modulo period size (to determine when a period is
finished).
Properties.
*/
unsigned
bytes_in
;
struct
line6_pcm_properties
*
properties
;
/**
Counter to create desired capture sample rate.
ALSA pcm stream
*/
unsigned
count_in
;
struct
snd_pcm
*
pcm
;
/**
Capture period size in bytes
*/
unsigned
period_in
;
/* protection to state changes of in/out streams */
struct
mutex
state_mutex
;
/* Capture and playback streams */
struct
line6_pcm_stream
in
;
struct
line6_pcm_stream
out
;
/**
Processed frame position in the capture buffer.
The contents of the output ring buffer have been consumed by
the USB subsystem (i.e., sent to the USB device) up to this
position.
Previously captured frame (for software monitoring).
*/
snd_pcm_uframes_t
pos_in_done
;
unsigned
char
*
prev_fbuf
;
/**
Bit mask of active playback URBs
.
Size of previously captured frame (for software monitoring)
.
*/
unsigned
long
active_urb_out
;
int
prev_fsize
;
/**
Maximum size of USB packet.
*/
int
max_packet_size
;
/**
Bit mask of active capture URBs.
*/
unsigned
long
active_urb_in
;
/**
Bit mask of playback URBs currently being unlinked.
*/
unsigned
long
unlink_urb_out
;
/**
Bit mask of capture URBs currently being unlinked.
*/
unsigned
long
unlink_urb_in
;
/**
Spin lock to protect updates of the playback buffer positions (not
contents!)
*/
spinlock_t
lock_audio_out
;
/**
Spin lock to protect updates of the capture buffer positions (not
contents!)
*/
spinlock_t
lock_audio_in
;
/**
Spin lock to protect trigger.
*/
spinlock_t
lock_trigger
;
/**
PCM playback volume (left and right).
*/
...
...
@@ -338,19 +202,21 @@ struct snd_line6_pcm {
int
impulse_count
;
/**
Several status bits (see LINE6_
BIT
_*).
Several status bits (see LINE6_
FLAG
_*).
*/
unsigned
long
flags
;
int
last_frame_in
,
last_frame_out
;
};
extern
int
line6_init_pcm
(
struct
usb_line6
*
line6
,
struct
line6_pcm_properties
*
properties
);
extern
int
snd_line6_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
);
extern
int
snd_line6_prepare
(
struct
snd_pcm_substream
*
substream
);
extern
int
snd_line6_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
hw_params
);
extern
int
snd_line6_hw_free
(
struct
snd_pcm_substream
*
substream
);
extern
snd_pcm_uframes_t
snd_line6_pointer
(
struct
snd_pcm_substream
*
substream
);
extern
void
line6_pcm_disconnect
(
struct
snd_line6_pcm
*
line6pcm
);
extern
int
line6_pcm_acquire
(
struct
snd_line6_pcm
*
line6pcm
,
int
channels
);
extern
int
line6_pcm_release
(
struct
snd_line6_pcm
*
line6pcm
,
int
channels
);
extern
int
line6_pcm_acquire
(
struct
snd_line6_pcm
*
line6pcm
,
int
type
);
extern
void
line6_pcm_release
(
struct
snd_line6_pcm
*
line6pcm
,
int
type
);
#endif
sound/usb/line6/playback.c
浏览文件 @
5e0ddd07
...
...
@@ -37,7 +37,8 @@ static void change_volume(struct urb *urb_out, int volume[],
buf_end
=
p
+
urb_out
->
transfer_buffer_length
/
sizeof
(
*
p
);
for
(;
p
<
buf_end
;
++
p
)
{
*
p
=
(
*
p
*
volume
[
chn
&
1
])
>>
8
;
int
val
=
(
*
p
*
volume
[
chn
&
1
])
>>
8
;
*
p
=
clamp
(
val
,
0x7fff
,
-
0x8000
);
++
chn
;
}
}
else
if
(
bytes_per_frame
==
6
)
{
...
...
@@ -51,6 +52,7 @@ static void change_volume(struct urb *urb_out, int volume[],
val
=
p
[
0
]
+
(
p
[
1
]
<<
8
)
+
((
signed
char
)
p
[
2
]
<<
16
);
val
=
(
val
*
volume
[
chn
&
1
])
>>
8
;
val
=
clamp
(
val
,
0x7fffff
,
-
0x800000
);
p
[
0
]
=
val
;
p
[
1
]
=
val
>>
8
;
p
[
2
]
=
val
>>
16
;
...
...
@@ -118,8 +120,10 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
po
=
(
short
*
)
urb_out
->
transfer_buffer
;
buf_end
=
po
+
urb_out
->
transfer_buffer_length
/
sizeof
(
*
po
);
for
(;
po
<
buf_end
;
++
pi
,
++
po
)
*
po
+=
(
*
pi
*
volume
)
>>
8
;
for
(;
po
<
buf_end
;
++
pi
,
++
po
)
{
int
val
=
*
po
+
((
*
pi
*
volume
)
>>
8
);
*
po
=
clamp
(
val
,
0x7fff
,
-
0x8000
);
}
}
/*
...
...
@@ -130,11 +134,11 @@ static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
/*
Find a free URB, prepare audio data, and submit URB.
must be called in line6pcm->out.lock context
*/
static
int
submit_audio_out_urb
(
struct
snd_line6_pcm
*
line6pcm
)
{
int
index
;
unsigned
long
flags
;
int
i
,
urb_size
,
urb_frames
;
int
ret
;
const
int
bytes_per_frame
=
line6pcm
->
properties
->
bytes_per_frame
;
...
...
@@ -145,17 +149,15 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
(
USB_INTERVALS_PER_SECOND
/
LINE6_ISO_INTERVAL
);
struct
urb
*
urb_out
;
spin_lock_irqsave
(
&
line6pcm
->
lock_audio_out
,
flags
);
index
=
find_first_zero_bit
(
&
line6pcm
->
active_urb_out
,
LINE6_ISO_BUFFERS
);
find_first_zero_bit
(
&
line6pcm
->
out
.
active_urbs
,
LINE6_ISO_BUFFERS
);
if
(
index
<
0
||
index
>=
LINE6_ISO_BUFFERS
)
{
spin_unlock_irqrestore
(
&
line6pcm
->
lock_audio_out
,
flags
);
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"no free URB found
\n
"
);
return
-
EINVAL
;
}
urb_out
=
line6pcm
->
urb_audio_out
[
index
];
urb_out
=
line6pcm
->
out
.
urbs
[
index
];
urb_size
=
0
;
for
(
i
=
0
;
i
<
LINE6_ISO_PACKETS
;
++
i
)
{
...
...
@@ -164,15 +166,13 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
struct
usb_iso_packet_descriptor
*
fout
=
&
urb_out
->
iso_frame_desc
[
i
];
if
(
line6pcm
->
flags
&
LINE6_BITS_CAPTURE_STREAM
)
fsize
=
line6pcm
->
prev_fsize
;
fsize
=
line6pcm
->
prev_fsize
;
if
(
fsize
==
0
)
{
int
n
;
line6pcm
->
count_ou
t
+=
frame_increment
;
n
=
line6pcm
->
count_ou
t
/
frame_factor
;
line6pcm
->
count_ou
t
-=
n
*
frame_factor
;
line6pcm
->
out
.
coun
t
+=
frame_increment
;
n
=
line6pcm
->
out
.
coun
t
/
frame_factor
;
line6pcm
->
out
.
coun
t
-=
n
*
frame_factor
;
fsize
=
n
*
bytes_per_frame
;
}
...
...
@@ -183,36 +183,35 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
if
(
urb_size
==
0
)
{
/* can't determine URB size */
spin_unlock_irqrestore
(
&
line6pcm
->
lock_audio_out
,
flags
);
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"driver bug: urb_size = 0
\n
"
);
return
-
EINVAL
;
}
urb_frames
=
urb_size
/
bytes_per_frame
;
urb_out
->
transfer_buffer
=
line6pcm
->
buffer_out
+
line6pcm
->
out
.
buffer
+
index
*
LINE6_ISO_PACKETS
*
line6pcm
->
max_packet_size
;
urb_out
->
transfer_buffer_length
=
urb_size
;
urb_out
->
context
=
line6pcm
;
if
(
test_bit
(
LINE6_
INDEX_PCM_ALSA_PLAYBACK_STREAM
,
&
line6pcm
->
flags
)
&&
!
test_bit
(
LINE6_
INDEX
_PAUSE_PLAYBACK
,
&
line6pcm
->
flags
))
{
if
(
test_bit
(
LINE6_
STREAM_PCM
,
&
line6pcm
->
out
.
running
)
&&
!
test_bit
(
LINE6_
FLAG
_PAUSE_PLAYBACK
,
&
line6pcm
->
flags
))
{
struct
snd_pcm_runtime
*
runtime
=
get_substream
(
line6pcm
,
SNDRV_PCM_STREAM_PLAYBACK
)
->
runtime
;
if
(
line6pcm
->
pos_out
+
urb_frames
>
runtime
->
buffer_size
)
{
if
(
line6pcm
->
out
.
pos
+
urb_frames
>
runtime
->
buffer_size
)
{
/*
The transferred area goes over buffer boundary,
copy the data to the temp buffer.
*/
int
len
;
len
=
runtime
->
buffer_size
-
line6pcm
->
pos_out
;
len
=
runtime
->
buffer_size
-
line6pcm
->
out
.
pos
;
if
(
len
>
0
)
{
memcpy
(
urb_out
->
transfer_buffer
,
runtime
->
dma_area
+
line6pcm
->
pos_out
*
bytes_per_frame
,
line6pcm
->
out
.
pos
*
bytes_per_frame
,
len
*
bytes_per_frame
);
memcpy
(
urb_out
->
transfer_buffer
+
len
*
bytes_per_frame
,
runtime
->
dma_area
,
...
...
@@ -223,26 +222,27 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
}
else
{
memcpy
(
urb_out
->
transfer_buffer
,
runtime
->
dma_area
+
line6pcm
->
pos_out
*
bytes_per_frame
,
line6pcm
->
out
.
pos
*
bytes_per_frame
,
urb_out
->
transfer_buffer_length
);
}
line6pcm
->
pos_out
+=
urb_frames
;
if
(
line6pcm
->
pos_out
>=
runtime
->
buffer_size
)
line6pcm
->
pos_out
-=
runtime
->
buffer_size
;
line6pcm
->
out
.
pos
+=
urb_frames
;
if
(
line6pcm
->
out
.
pos
>=
runtime
->
buffer_size
)
line6pcm
->
out
.
pos
-=
runtime
->
buffer_size
;
change_volume
(
urb_out
,
line6pcm
->
volume_playback
,
bytes_per_frame
);
}
else
{
memset
(
urb_out
->
transfer_buffer
,
0
,
urb_out
->
transfer_buffer_length
);
}
change_volume
(
urb_out
,
line6pcm
->
volume_playback
,
bytes_per_frame
);
if
(
line6pcm
->
prev_fbuf
!=
NULL
)
{
if
(
line6pcm
->
flags
&
LINE6_BITS_PCM_IMPULSE
)
{
spin_lock_nested
(
&
line6pcm
->
in
.
lock
,
SINGLE_DEPTH_NESTING
);
if
(
line6pcm
->
prev_fbuf
)
{
if
(
test_bit
(
LINE6_STREAM_IMPULSE
,
&
line6pcm
->
out
.
running
))
{
create_impulse_test_signal
(
line6pcm
,
urb_out
,
bytes_per_frame
);
if
(
line6pcm
->
flags
&
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM
)
{
if
(
test_bit
(
LINE6_STREAM_PCM
,
&
line6pcm
->
in
.
running
))
{
line6_capture_copy
(
line6pcm
,
urb_out
->
transfer_buffer
,
urb_out
->
...
...
@@ -251,101 +251,43 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
urb_out
->
transfer_buffer_length
);
}
}
else
{
if
(
!
(
line6pcm
->
line6
->
properties
->
capabilities
&
LINE6_CAP_HWMON
)
&&
(
line6pcm
->
flags
&
LINE6_BITS_PLAYBACK_STREAM
)
&&
(
line6pcm
->
flags
&
LINE6_BITS_CAPTURE_STREAM
))
if
(
!
(
line6pcm
->
line6
->
properties
->
capabilities
&
LINE6_CAP_HWMON
)
&&
line6pcm
->
out
.
running
&&
line6pcm
->
in
.
running
)
add_monitor_signal
(
urb_out
,
line6pcm
->
prev_fbuf
,
line6pcm
->
volume_monitor
,
bytes_per_frame
);
}
line6pcm
->
prev_fbuf
=
NULL
;
line6pcm
->
prev_fsize
=
0
;
}
spin_unlock
(
&
line6pcm
->
in
.
lock
);
ret
=
usb_submit_urb
(
urb_out
,
GFP_ATOMIC
);
if
(
ret
==
0
)
set_bit
(
index
,
&
line6pcm
->
active_urb_out
);
set_bit
(
index
,
&
line6pcm
->
out
.
active_urbs
);
else
dev_err
(
line6pcm
->
line6
->
ifcdev
,
"URB out #%d submission failed (%d)
\n
"
,
index
,
ret
);
spin_unlock_irqrestore
(
&
line6pcm
->
lock_audio_out
,
flags
);
return
0
;
}
/*
Submit all currently available playback URBs.
*/
must be called in line6pcm->out.lock context
*/
int
line6_submit_audio_out_all_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
{
int
ret
,
i
;
int
ret
=
0
,
i
;
for
(
i
=
0
;
i
<
LINE6_ISO_BUFFERS
;
++
i
)
{
ret
=
submit_audio_out_urb
(
line6pcm
);
if
(
ret
<
0
)
return
ret
;
}
return
0
;
}
/*
Unlink all currently active playback URBs.
*/
void
line6_unlink_audio_out_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
{
unsigned
int
i
;
for
(
i
=
LINE6_ISO_BUFFERS
;
i
--
;)
{
if
(
test_bit
(
i
,
&
line6pcm
->
active_urb_out
))
{
if
(
!
test_and_set_bit
(
i
,
&
line6pcm
->
unlink_urb_out
))
{
struct
urb
*
u
=
line6pcm
->
urb_audio_out
[
i
];
usb_unlink_urb
(
u
);
}
}
}
}
/*
Wait until unlinking of all currently active playback URBs has been
finished.
*/
void
line6_wait_clear_audio_out_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
{
int
timeout
=
HZ
;
unsigned
int
i
;
int
alive
;
do
{
alive
=
0
;
for
(
i
=
LINE6_ISO_BUFFERS
;
i
--
;)
{
if
(
test_bit
(
i
,
&
line6pcm
->
active_urb_out
))
alive
++
;
}
if
(
!
alive
)
break
;
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
1
);
}
while
(
--
timeout
>
0
);
if
(
alive
)
snd_printk
(
KERN_ERR
"timeout: still %d active urbs..
\n
"
,
alive
);
}
/*
Unlink all currently active playback URBs, and wait for finishing.
*/
void
line6_unlink_wait_clear_audio_out_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
{
line6_unlink_audio_out_urbs
(
line6pcm
);
line6_wait_clear_audio_out_urbs
(
line6pcm
);
}
}
void
line6_free_playback_buffer
(
struct
snd_line6_pcm
*
line6pcm
)
{
kfree
(
line6pcm
->
buffer_out
);
line6pcm
->
buffer_out
=
NULL
;
return
ret
;
}
/*
...
...
@@ -363,56 +305,56 @@ static void audio_out_callback(struct urb *urb)
memset
(
urb
->
transfer_buffer
,
0
,
urb
->
transfer_buffer_length
);
#endif
line6pcm
->
last_frame_out
=
urb
->
start_frame
;
line6pcm
->
out
.
last_frame
=
urb
->
start_frame
;
/* find index of URB */
for
(
index
=
LINE6_ISO_BUFFERS
;
index
--
;
)
if
(
urb
==
line6pcm
->
urb_audio_out
[
index
])
for
(
index
=
0
;
index
<
LINE6_ISO_BUFFERS
;
index
++
)
if
(
urb
==
line6pcm
->
out
.
urbs
[
index
])
break
;
if
(
index
<
0
)
if
(
index
>=
LINE6_ISO_BUFFERS
)
return
;
/* URB has been unlinked asynchronously */
for
(
i
=
LINE6_ISO_PACKETS
;
i
--
;
)
for
(
i
=
0
;
i
<
LINE6_ISO_PACKETS
;
i
++
)
length
+=
urb
->
iso_frame_desc
[
i
].
length
;
spin_lock_irqsave
(
&
line6pcm
->
lock_audio_out
,
flags
);
spin_lock_irqsave
(
&
line6pcm
->
out
.
lock
,
flags
);
if
(
test_bit
(
LINE6_
INDEX_PCM_ALSA_PLAYBACK_STREAM
,
&
line6pcm
->
flags
))
{
if
(
test_bit
(
LINE6_
STREAM_PCM
,
&
line6pcm
->
out
.
running
))
{
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
line6pcm
->
pos_out
_done
+=
line6pcm
->
out
.
pos
_done
+=
length
/
line6pcm
->
properties
->
bytes_per_frame
;
if
(
line6pcm
->
pos_out
_done
>=
runtime
->
buffer_size
)
line6pcm
->
pos_out
_done
-=
runtime
->
buffer_size
;
if
(
line6pcm
->
out
.
pos
_done
>=
runtime
->
buffer_size
)
line6pcm
->
out
.
pos
_done
-=
runtime
->
buffer_size
;
}
clear_bit
(
index
,
&
line6pcm
->
active_urb_out
);
clear_bit
(
index
,
&
line6pcm
->
out
.
active_urbs
);
for
(
i
=
LINE6_ISO_PACKETS
;
i
--
;
)
for
(
i
=
0
;
i
<
LINE6_ISO_PACKETS
;
i
++
)
if
(
urb
->
iso_frame_desc
[
i
].
status
==
-
EXDEV
)
{
shutdown
=
1
;
break
;
}
if
(
test_and_clear_bit
(
index
,
&
line6pcm
->
unlink_urb_out
))
if
(
test_and_clear_bit
(
index
,
&
line6pcm
->
out
.
unlink_urbs
))
shutdown
=
1
;
spin_unlock_irqrestore
(
&
line6pcm
->
lock_audio_out
,
flags
);
if
(
!
shutdown
)
{
submit_audio_out_urb
(
line6pcm
);
if
(
test_bit
(
LINE6_
INDEX_PCM_ALSA_PLAYBACK_STREAM
,
&
line6pcm
->
flags
))
{
line6pcm
->
bytes_out
+=
length
;
if
(
line6pcm
->
bytes_out
>=
line6pcm
->
period_out
)
{
line6pcm
->
bytes_out
%=
line6pcm
->
period_out
;
if
(
test_bit
(
LINE6_
STREAM_PCM
,
&
line6pcm
->
out
.
running
))
{
line6pcm
->
out
.
bytes
+=
length
;
if
(
line6pcm
->
out
.
bytes
>=
line6pcm
->
out
.
period
)
{
line6pcm
->
out
.
bytes
%=
line6pcm
->
out
.
period
;
spin_unlock
(
&
line6pcm
->
out
.
lock
)
;
snd_pcm_period_elapsed
(
substream
);
spin_lock
(
&
line6pcm
->
out
.
lock
);
}
}
}
spin_unlock_irqrestore
(
&
line6pcm
->
out
.
lock
,
flags
);
}
/* open playback callback */
...
...
@@ -438,110 +380,16 @@ static int snd_line6_playback_close(struct snd_pcm_substream *substream)
return
0
;
}
/* hw_params playback callback */
static
int
snd_line6_playback_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
hw_params
)
{
int
ret
;
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
/* -- Florian Demski [FD] */
/* don't ask me why, but this fixes the bug on my machine */
if
(
line6pcm
==
NULL
)
{
if
(
substream
->
pcm
==
NULL
)
return
-
ENOMEM
;
if
(
substream
->
pcm
->
private_data
==
NULL
)
return
-
ENOMEM
;
substream
->
private_data
=
substream
->
pcm
->
private_data
;
line6pcm
=
snd_pcm_substream_chip
(
substream
);
}
/* -- [FD] end */
ret
=
line6_pcm_acquire
(
line6pcm
,
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER
);
if
(
ret
<
0
)
return
ret
;
ret
=
snd_pcm_lib_malloc_pages
(
substream
,
params_buffer_bytes
(
hw_params
));
if
(
ret
<
0
)
{
line6_pcm_release
(
line6pcm
,
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER
);
return
ret
;
}
line6pcm
->
period_out
=
params_period_bytes
(
hw_params
);
return
0
;
}
/* hw_free playback callback */
static
int
snd_line6_playback_hw_free
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
line6_pcm_release
(
line6pcm
,
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER
);
return
snd_pcm_lib_free_pages
(
substream
);
}
/* trigger playback callback */
int
snd_line6_playback_trigger
(
struct
snd_line6_pcm
*
line6pcm
,
int
cmd
)
{
int
err
;
switch
(
cmd
)
{
case
SNDRV_PCM_TRIGGER_START
:
case
SNDRV_PCM_TRIGGER_RESUME
:
err
=
line6_pcm_acquire
(
line6pcm
,
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM
);
if
(
err
<
0
)
return
err
;
break
;
case
SNDRV_PCM_TRIGGER_STOP
:
case
SNDRV_PCM_TRIGGER_SUSPEND
:
err
=
line6_pcm_release
(
line6pcm
,
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM
);
if
(
err
<
0
)
return
err
;
break
;
case
SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
set_bit
(
LINE6_INDEX_PAUSE_PLAYBACK
,
&
line6pcm
->
flags
);
break
;
case
SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
clear_bit
(
LINE6_INDEX_PAUSE_PLAYBACK
,
&
line6pcm
->
flags
);
break
;
default:
return
-
EINVAL
;
}
return
0
;
}
/* playback pointer callback */
static
snd_pcm_uframes_t
snd_line6_playback_pointer
(
struct
snd_pcm_substream
*
substream
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_pcm_substream_chip
(
substream
);
return
line6pcm
->
pos_out_done
;
}
/* playback operators */
struct
snd_pcm_ops
snd_line6_playback_ops
=
{
.
open
=
snd_line6_playback_open
,
.
close
=
snd_line6_playback_close
,
.
ioctl
=
snd_pcm_lib_ioctl
,
.
hw_params
=
snd_line6_
playback_
hw_params
,
.
hw_free
=
snd_line6_
playback_
hw_free
,
.
hw_params
=
snd_line6_hw_params
,
.
hw_free
=
snd_line6_hw_free
,
.
prepare
=
snd_line6_prepare
,
.
trigger
=
snd_line6_trigger
,
.
pointer
=
snd_line6_p
layback_p
ointer
,
.
pointer
=
snd_line6_pointer
,
};
int
line6_create_audio_out_urbs
(
struct
snd_line6_pcm
*
line6pcm
)
...
...
@@ -554,7 +402,7 @@ int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
struct
urb
*
urb
;
/* URB for audio out: */
urb
=
line6pcm
->
urb_audio_out
[
i
]
=
urb
=
line6pcm
->
out
.
urbs
[
i
]
=
usb_alloc_urb
(
LINE6_ISO_PACKETS
,
GFP_KERNEL
);
if
(
urb
==
NULL
)
...
...
sound/usb/line6/playback.h
浏览文件 @
5e0ddd07
...
...
@@ -30,12 +30,6 @@
extern
struct
snd_pcm_ops
snd_line6_playback_ops
;
extern
int
line6_create_audio_out_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
void
line6_free_playback_buffer
(
struct
snd_line6_pcm
*
line6pcm
);
extern
int
line6_submit_audio_out_all_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
void
line6_unlink_audio_out_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
void
line6_unlink_wait_clear_audio_out_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
void
line6_wait_clear_audio_out_urbs
(
struct
snd_line6_pcm
*
line6pcm
);
extern
int
snd_line6_playback_trigger
(
struct
snd_line6_pcm
*
line6pcm
,
int
cmd
);
#endif
sound/usb/line6/pod.c
浏览文件 @
5e0ddd07
...
...
@@ -399,27 +399,18 @@ static struct snd_kcontrol_new pod_control_monitor = {
/*
POD device disconnected.
*/
static
void
line6_pod_disconnect
(
struct
usb_
interface
*
interface
)
static
void
line6_pod_disconnect
(
struct
usb_
line6
*
line6
)
{
struct
usb_line6_pod
*
pod
;
struct
usb_line6_pod
*
pod
=
(
struct
usb_line6_pod
*
)
line6
;
struct
device
*
dev
=
line6
->
ifcdev
;
if
(
interface
==
NULL
)
return
;
pod
=
usb_get_intfdata
(
interface
);
if
(
pod
!=
NULL
)
{
struct
device
*
dev
=
&
interface
->
dev
;
if
(
dev
!=
NULL
)
{
/* remove sysfs entries: */
device_remove_file
(
dev
,
&
dev_attr_device_id
);
device_remove_file
(
dev
,
&
dev_attr_firmware_version
);
device_remove_file
(
dev
,
&
dev_attr_serial_number
);
}
/* remove sysfs entries: */
device_remove_file
(
dev
,
&
dev_attr_device_id
);
device_remove_file
(
dev
,
&
dev_attr_firmware_version
);
device_remove_file
(
dev
,
&
dev_attr_serial_number
);
del_timer_sync
(
&
pod
->
startup_timer
);
cancel_work_sync
(
&
pod
->
startup_work
);
}
del_timer_sync
(
&
pod
->
startup_timer
);
cancel_work_sync
(
&
pod
->
startup_work
);
}
/*
...
...
@@ -444,8 +435,8 @@ static int pod_create_files2(struct device *dev)
/*
Try to init POD device.
*/
static
int
pod_init
(
struct
usb_
interface
*
interface
,
struct
usb_line6
*
line6
)
static
int
pod_init
(
struct
usb_
line6
*
line6
,
const
struct
usb_device_id
*
id
)
{
int
err
;
struct
usb_line6_pod
*
pod
=
(
struct
usb_line6_pod
*
)
line6
;
...
...
@@ -456,11 +447,8 @@ static int pod_init(struct usb_interface *interface,
init_timer
(
&
pod
->
startup_timer
);
INIT_WORK
(
&
pod
->
startup_work
,
pod_startup4
);
if
((
interface
==
NULL
)
||
(
pod
==
NULL
))
return
-
ENODEV
;
/* create sysfs entries: */
err
=
pod_create_files2
(
&
interface
->
dev
);
err
=
pod_create_files2
(
line6
->
ifc
dev
);
if
(
err
<
0
)
return
err
;
...
...
@@ -603,14 +591,9 @@ static const struct line6_properties pod_properties_table[] = {
static
int
pod_probe
(
struct
usb_interface
*
interface
,
const
struct
usb_device_id
*
id
)
{
struct
usb_line6_pod
*
pod
;
pod
=
kzalloc
(
sizeof
(
*
pod
),
GFP_KERNEL
);
if
(
!
pod
)
return
-
ENODEV
;
return
line6_probe
(
interface
,
&
pod
->
line6
,
return
line6_probe
(
interface
,
id
,
&
pod_properties_table
[
id
->
driver_info
],
pod_init
);
pod_init
,
sizeof
(
struct
usb_line6_pod
)
);
}
static
struct
usb_driver
pod_driver
=
{
...
...
sound/usb/line6/podhd.c
浏览文件 @
5e0ddd07
...
...
@@ -87,15 +87,11 @@ static struct line6_pcm_properties podhd_pcm_properties = {
/*
Try to init POD HD device.
*/
static
int
podhd_init
(
struct
usb_
interface
*
interface
,
struct
usb_line6
*
line6
)
static
int
podhd_init
(
struct
usb_
line6
*
line6
,
const
struct
usb_device_id
*
id
)
{
struct
usb_line6_podhd
*
podhd
=
(
struct
usb_line6_podhd
*
)
line6
;
int
err
;
if
((
interface
==
NULL
)
||
(
podhd
==
NULL
))
return
-
ENODEV
;
/* initialize MIDI subsystem: */
err
=
line6_init_midi
(
line6
);
if
(
err
<
0
)
...
...
@@ -181,14 +177,9 @@ static const struct line6_properties podhd_properties_table[] = {
static
int
podhd_probe
(
struct
usb_interface
*
interface
,
const
struct
usb_device_id
*
id
)
{
struct
usb_line6_podhd
*
podhd
;
podhd
=
kzalloc
(
sizeof
(
*
podhd
),
GFP_KERNEL
);
if
(
!
podhd
)
return
-
ENODEV
;
return
line6_probe
(
interface
,
&
podhd
->
line6
,
return
line6_probe
(
interface
,
id
,
&
podhd_properties_table
[
id
->
driver_info
],
podhd_init
);
podhd_init
,
sizeof
(
struct
usb_line6_podhd
)
);
}
static
struct
usb_driver
podhd_driver
=
{
...
...
sound/usb/line6/toneport.c
浏览文件 @
5e0ddd07
...
...
@@ -14,6 +14,7 @@
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <sound/core.h>
#include <sound/control.h>
...
...
@@ -32,6 +33,15 @@ enum line6_device_type {
LINE6_TONEPORT_UX2
,
};
struct
usb_line6_toneport
;
struct
toneport_led
{
struct
led_classdev
dev
;
char
name
[
64
];
struct
usb_line6_toneport
*
toneport
;
bool
registered
;
};
struct
usb_line6_toneport
{
/**
Generic Line 6 USB data.
...
...
@@ -62,6 +72,9 @@ struct usb_line6_toneport {
Device type.
*/
enum
line6_device_type
type
;
/* LED instances */
struct
toneport_led
leds
[
2
];
};
static
int
toneport_send_cmd
(
struct
usb_device
*
usbdev
,
int
cmd1
,
int
cmd2
);
...
...
@@ -117,15 +130,6 @@ static struct line6_pcm_properties toneport_pcm_properties = {
.
bytes_per_frame
=
4
};
/*
For the led on Guitarport.
Brightness goes from 0x00 to 0x26. Set a value above this to have led
blink.
(void cmd_0x02(byte red, byte green)
*/
static
int
led_red
=
0x00
;
static
int
led_green
=
0x26
;
static
const
struct
{
const
char
*
name
;
int
code
;
...
...
@@ -136,62 +140,6 @@ static const struct {
{
"Inst & Mic"
,
0x0901
}
};
static
bool
toneport_has_led
(
enum
line6_device_type
type
)
{
return
(
type
==
LINE6_GUITARPORT
)
||
(
type
==
LINE6_TONEPORT_GX
);
/* add your device here if you are missing support for the LEDs */
}
static
void
toneport_update_led
(
struct
device
*
dev
)
{
struct
usb_interface
*
interface
=
to_usb_interface
(
dev
);
struct
usb_line6_toneport
*
tp
=
usb_get_intfdata
(
interface
);
struct
usb_line6
*
line6
;
if
(
!
tp
)
return
;
line6
=
&
tp
->
line6
;
if
(
line6
)
toneport_send_cmd
(
line6
->
usbdev
,
(
led_red
<<
8
)
|
0x0002
,
led_green
);
}
static
ssize_t
toneport_set_led_red
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
int
retval
;
retval
=
kstrtoint
(
buf
,
10
,
&
led_red
);
if
(
retval
)
return
retval
;
toneport_update_led
(
dev
);
return
count
;
}
static
ssize_t
toneport_set_led_green
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
int
retval
;
retval
=
kstrtoint
(
buf
,
10
,
&
led_green
);
if
(
retval
)
return
retval
;
toneport_update_led
(
dev
);
return
count
;
}
static
DEVICE_ATTR
(
led_red
,
S_IWUSR
|
S_IRUGO
,
line6_nop_read
,
toneport_set_led_red
);
static
DEVICE_ATTR
(
led_green
,
S_IWUSR
|
S_IRUGO
,
line6_nop_read
,
toneport_set_led_green
);
static
int
toneport_send_cmd
(
struct
usb_device
*
usbdev
,
int
cmd1
,
int
cmd2
)
{
int
ret
;
...
...
@@ -234,16 +182,23 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
struct
snd_ctl_elem_value
*
ucontrol
)
{
struct
snd_line6_pcm
*
line6pcm
=
snd_kcontrol_chip
(
kcontrol
);
int
err
;
if
(
ucontrol
->
value
.
integer
.
value
[
0
]
==
line6pcm
->
volume_monitor
)
return
0
;
line6pcm
->
volume_monitor
=
ucontrol
->
value
.
integer
.
value
[
0
];
if
(
line6pcm
->
volume_monitor
>
0
)
line6_pcm_acquire
(
line6pcm
,
LINE6_BITS_PCM_MONITOR
);
else
line6_pcm_release
(
line6pcm
,
LINE6_BITS_PCM_MONITOR
);
if
(
line6pcm
->
volume_monitor
>
0
)
{
err
=
line6_pcm_acquire
(
line6pcm
,
LINE6_STREAM_MONITOR
);
if
(
err
<
0
)
{
line6pcm
->
volume_monitor
=
0
;
line6_pcm_release
(
line6pcm
,
LINE6_STREAM_MONITOR
);
return
err
;
}
}
else
{
line6_pcm_release
(
line6pcm
,
LINE6_STREAM_MONITOR
);
}
return
1
;
}
...
...
@@ -304,7 +259,7 @@ static void toneport_start_pcm(unsigned long arg)
struct
usb_line6_toneport
*
toneport
=
(
struct
usb_line6_toneport
*
)
arg
;
struct
usb_line6
*
line6
=
&
toneport
->
line6
;
line6_pcm_acquire
(
line6
->
line6pcm
,
LINE6_
BITS_PC
M_MONITOR
);
line6_pcm_acquire
(
line6
->
line6pcm
,
LINE6_
STREA
M_MONITOR
);
}
/* control definition */
...
...
@@ -329,6 +284,78 @@ static struct snd_kcontrol_new toneport_control_source = {
.
put
=
snd_toneport_source_put
};
/*
For the led on Guitarport.
Brightness goes from 0x00 to 0x26. Set a value above this to have led
blink.
(void cmd_0x02(byte red, byte green)
*/
static
bool
toneport_has_led
(
enum
line6_device_type
type
)
{
return
(
type
==
LINE6_GUITARPORT
)
||
(
type
==
LINE6_TONEPORT_GX
);
/* add your device here if you are missing support for the LEDs */
}
static
const
char
*
const
led_colors
[
2
]
=
{
"red"
,
"green"
};
static
const
int
led_init_vals
[
2
]
=
{
0x00
,
0x26
};
static
void
toneport_update_led
(
struct
usb_line6_toneport
*
toneport
)
{
toneport_send_cmd
(
toneport
->
line6
.
usbdev
,
(
toneport
->
leds
[
0
].
dev
.
brightness
<<
8
)
|
0x0002
,
toneport
->
leds
[
1
].
dev
.
brightness
);
}
static
void
toneport_led_brightness_set
(
struct
led_classdev
*
led_cdev
,
enum
led_brightness
brightness
)
{
struct
toneport_led
*
leds
=
container_of
(
led_cdev
,
struct
toneport_led
,
dev
);
toneport_update_led
(
leds
->
toneport
);
}
static
int
toneport_init_leds
(
struct
usb_line6_toneport
*
toneport
)
{
struct
device
*
dev
=
&
toneport
->
line6
.
usbdev
->
dev
;
int
i
,
err
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
struct
toneport_led
*
led
=
&
toneport
->
leds
[
i
];
struct
led_classdev
*
leddev
=
&
led
->
dev
;
led
->
toneport
=
toneport
;
snprintf
(
led
->
name
,
sizeof
(
led
->
name
),
"%s::%s"
,
dev_name
(
dev
),
led_colors
[
i
]);
leddev
->
name
=
led
->
name
;
leddev
->
brightness
=
led_init_vals
[
i
];
leddev
->
max_brightness
=
0x26
;
leddev
->
brightness_set
=
toneport_led_brightness_set
;
err
=
led_classdev_register
(
dev
,
leddev
);
if
(
err
)
return
err
;
led
->
registered
=
true
;
}
return
0
;
}
static
void
toneport_remove_leds
(
struct
usb_line6_toneport
*
toneport
)
{
struct
toneport_led
*
led
;
int
i
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
led
=
&
toneport
->
leds
[
i
];
if
(
!
led
->
registered
)
break
;
led_classdev_unregister
(
&
led
->
dev
);
led
->
registered
=
false
;
}
}
/*
Setup Toneport device.
*/
...
...
@@ -359,42 +386,38 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
}
if
(
toneport_has_led
(
toneport
->
type
))
toneport_update_led
(
&
usbdev
->
dev
);
toneport_update_led
(
toneport
);
mod_timer
(
&
toneport
->
timer
,
jiffies
+
TONEPORT_PCM_DELAY
*
HZ
);
}
/*
Toneport device disconnected.
*/
static
void
line6_toneport_disconnect
(
struct
usb_
interface
*
interface
)
static
void
line6_toneport_disconnect
(
struct
usb_
line6
*
line6
)
{
struct
usb_line6_toneport
*
toneport
;
u16
idProduct
;
if
(
interface
==
NULL
)
return
;
struct
usb_line6_toneport
*
toneport
=
(
struct
usb_line6_toneport
*
)
line6
;
toneport
=
usb_get_intfdata
(
interface
);
del_timer_sync
(
&
toneport
->
timer
);
idProduct
=
le16_to_cpu
(
toneport
->
line6
.
usbdev
->
descriptor
.
idProduct
);
if
(
toneport_has_led
(
idProduct
))
{
device_remove_file
(
&
interface
->
dev
,
&
dev_attr_led_red
);
device_remove_file
(
&
interface
->
dev
,
&
dev_attr_led_green
);
}
if
(
toneport_has_led
(
toneport
->
type
))
toneport_remove_leds
(
toneport
);
}
/*
Try to init Toneport device.
*/
static
int
toneport_init
(
struct
usb_
interface
*
interface
,
struct
usb_line6
*
line6
)
static
int
toneport_init
(
struct
usb_
line6
*
line6
,
const
struct
usb_device_id
*
id
)
{
int
err
;
struct
usb_line6_toneport
*
toneport
=
(
struct
usb_line6_toneport
*
)
line6
;
if
((
interface
==
NULL
)
||
(
toneport
==
NULL
))
return
-
ENODEV
;
toneport
->
type
=
id
->
driver_info
;
setup_timer
(
&
toneport
->
timer
,
toneport_start_pcm
,
(
unsigned
long
)
toneport
);
line6
->
disconnect
=
line6_toneport_disconnect
;
...
...
@@ -431,20 +454,13 @@ static int toneport_init(struct usb_interface *interface,
line6_read_data
(
line6
,
0x80c2
,
&
toneport
->
firmware_version
,
1
);
if
(
toneport_has_led
(
toneport
->
type
))
{
err
=
device_create_file
(
&
interface
->
dev
,
&
dev_attr_led_red
);
if
(
err
<
0
)
return
err
;
err
=
device_create_file
(
&
interface
->
dev
,
&
dev_attr_led_green
);
err
=
toneport_init_leds
(
toneport
);
if
(
err
<
0
)
return
err
;
}
toneport_setup
(
toneport
);
setup_timer
(
&
toneport
->
timer
,
toneport_start_pcm
,
(
unsigned
long
)
toneport
);
mod_timer
(
&
toneport
->
timer
,
jiffies
+
TONEPORT_PCM_DELAY
*
HZ
);
/* register audio system: */
return
snd_card_register
(
line6
->
card
);
}
...
...
@@ -549,15 +565,9 @@ static const struct line6_properties toneport_properties_table[] = {
static
int
toneport_probe
(
struct
usb_interface
*
interface
,
const
struct
usb_device_id
*
id
)
{
struct
usb_line6_toneport
*
toneport
;
toneport
=
kzalloc
(
sizeof
(
*
toneport
),
GFP_KERNEL
);
if
(
!
toneport
)
return
-
ENODEV
;
toneport
->
type
=
id
->
driver_info
;
return
line6_probe
(
interface
,
&
toneport
->
line6
,
return
line6_probe
(
interface
,
id
,
&
toneport_properties_table
[
id
->
driver_info
],
toneport_init
);
toneport_init
,
sizeof
(
struct
usb_line6_toneport
)
);
}
static
struct
usb_driver
toneport_driver
=
{
...
...
sound/usb/line6/variax.c
浏览文件 @
5e0ddd07
...
...
@@ -210,16 +210,9 @@ static void line6_variax_process_message(struct usb_line6 *line6)
/*
Variax destructor.
*/
static
void
line6_variax_disconnect
(
struct
usb_
interface
*
interface
)
static
void
line6_variax_disconnect
(
struct
usb_
line6
*
line6
)
{
struct
usb_line6_variax
*
variax
;
if
(
!
interface
)
return
;
variax
=
usb_get_intfdata
(
interface
);
if
(
!
variax
)
return
;
struct
usb_line6_variax
*
variax
=
(
struct
usb_line6_variax
*
)
line6
;
del_timer
(
&
variax
->
startup_timer1
);
del_timer
(
&
variax
->
startup_timer2
);
...
...
@@ -231,8 +224,8 @@ static void line6_variax_disconnect(struct usb_interface *interface)
/*
Try to init workbench device.
*/
static
int
variax_init
(
struct
usb_
interface
*
interface
,
struct
usb_line6
*
line6
)
static
int
variax_init
(
struct
usb_
line6
*
line6
,
const
struct
usb_device_id
*
id
)
{
struct
usb_line6_variax
*
variax
=
(
struct
usb_line6_variax
*
)
line6
;
int
err
;
...
...
@@ -244,9 +237,6 @@ static int variax_init(struct usb_interface *interface,
init_timer
(
&
variax
->
startup_timer2
);
INIT_WORK
(
&
variax
->
startup_work
,
variax_startup6
);
if
((
interface
==
NULL
)
||
(
variax
==
NULL
))
return
-
ENODEV
;
/* initialize USB buffers: */
variax
->
buffer_activate
=
kmemdup
(
variax_activate
,
sizeof
(
variax_activate
),
GFP_KERNEL
);
...
...
@@ -306,14 +296,9 @@ static const struct line6_properties variax_properties_table[] = {
static
int
variax_probe
(
struct
usb_interface
*
interface
,
const
struct
usb_device_id
*
id
)
{
struct
usb_line6_variax
*
variax
;
variax
=
kzalloc
(
sizeof
(
*
variax
),
GFP_KERNEL
);
if
(
!
variax
)
return
-
ENODEV
;
return
line6_probe
(
interface
,
&
variax
->
line6
,
return
line6_probe
(
interface
,
id
,
&
variax_properties_table
[
id
->
driver_info
],
variax_init
);
variax_init
,
sizeof
(
struct
usb_line6_variax
)
);
}
static
struct
usb_driver
variax_driver
=
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录