diff options
-rw-r--r-- | sound/firewire/oxfw/Makefile | 2 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw-stream.c | 80 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw.c | 130 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw.h | 56 |
4 files changed, 159 insertions, 109 deletions
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 9ca49c0fdc40..e15c4c07b49d 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | snd-oxfw-objs := oxfw.o | 1 | snd-oxfw-objs := oxfw-stream.o oxfw.o |
2 | obj-m += snd-oxfw.o | 2 | obj-m += snd-oxfw.o |
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c new file mode 100644 index 000000000000..ebd156f3e29d --- /dev/null +++ b/sound/firewire/oxfw/oxfw-stream.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * oxfw_stream.c - a part of driver for OXFW970/971 based devices | ||
3 | * | ||
4 | * Copyright (c) 2014 Takashi Sakamoto | ||
5 | * | ||
6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "oxfw.h" | ||
10 | |||
11 | int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw) | ||
12 | { | ||
13 | int err; | ||
14 | |||
15 | err = cmp_connection_init(&oxfw->in_conn, oxfw->unit, | ||
16 | CMP_INPUT, 0); | ||
17 | if (err < 0) | ||
18 | goto end; | ||
19 | |||
20 | err = amdtp_stream_init(&oxfw->rx_stream, oxfw->unit, | ||
21 | AMDTP_OUT_STREAM, CIP_NONBLOCKING); | ||
22 | if (err < 0) { | ||
23 | amdtp_stream_destroy(&oxfw->rx_stream); | ||
24 | cmp_connection_destroy(&oxfw->in_conn); | ||
25 | } | ||
26 | end: | ||
27 | return err; | ||
28 | } | ||
29 | |||
30 | static void stop_stream(struct snd_oxfw *oxfw) | ||
31 | { | ||
32 | amdtp_stream_pcm_abort(&oxfw->rx_stream); | ||
33 | amdtp_stream_stop(&oxfw->rx_stream); | ||
34 | cmp_connection_break(&oxfw->in_conn); | ||
35 | } | ||
36 | |||
37 | int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw) | ||
38 | { | ||
39 | int err = 0; | ||
40 | |||
41 | if (amdtp_streaming_error(&oxfw->rx_stream)) | ||
42 | stop_stream(oxfw); | ||
43 | |||
44 | if (amdtp_stream_running(&oxfw->rx_stream)) | ||
45 | goto end; | ||
46 | |||
47 | err = cmp_connection_establish(&oxfw->in_conn, | ||
48 | amdtp_stream_get_max_payload(&oxfw->rx_stream)); | ||
49 | if (err < 0) | ||
50 | goto end; | ||
51 | |||
52 | err = amdtp_stream_start(&oxfw->rx_stream, | ||
53 | oxfw->in_conn.resources.channel, | ||
54 | oxfw->in_conn.speed); | ||
55 | if (err < 0) | ||
56 | stop_stream(oxfw); | ||
57 | end: | ||
58 | return err; | ||
59 | } | ||
60 | |||
61 | void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw) | ||
62 | { | ||
63 | stop_stream(oxfw); | ||
64 | } | ||
65 | |||
66 | void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw) | ||
67 | { | ||
68 | stop_stream(oxfw); | ||
69 | |||
70 | amdtp_stream_destroy(&oxfw->rx_stream); | ||
71 | cmp_connection_destroy(&oxfw->in_conn); | ||
72 | } | ||
73 | |||
74 | void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw) | ||
75 | { | ||
76 | if (cmp_connection_update(&oxfw->in_conn) < 0) | ||
77 | stop_stream(oxfw); | ||
78 | else | ||
79 | amdtp_stream_update(&oxfw->rx_stream); | ||
80 | } | ||
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 55c687ef3247..40556677ea07 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c | |||
@@ -5,22 +5,7 @@ | |||
5 | * Licensed under the terms of the GNU General Public License, version 2. | 5 | * Licensed under the terms of the GNU General Public License, version 2. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/device.h> | 8 | #include "oxfw.h" |
9 | #include <linux/firewire.h> | ||
10 | #include <linux/firewire-constants.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/mod_devicetable.h> | ||
13 | #include <linux/mutex.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <sound/control.h> | ||
16 | #include <sound/core.h> | ||
17 | #include <sound/initval.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include "../cmp.h" | ||
21 | #include "../fcp.h" | ||
22 | #include "../amdtp.h" | ||
23 | #include "../lib.h" | ||
24 | 9 | ||
25 | #define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) | 10 | #define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) |
26 | /* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ | 11 | /* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ |
@@ -35,29 +20,6 @@ | |||
35 | #define SPECIFIER_1394TA 0x00a02d | 20 | #define SPECIFIER_1394TA 0x00a02d |
36 | #define VERSION_AVC 0x010001 | 21 | #define VERSION_AVC 0x010001 |
37 | 22 | ||
38 | struct device_info { | ||
39 | const char *driver_name; | ||
40 | const char *short_name; | ||
41 | const char *long_name; | ||
42 | int (*pcm_constraints)(struct snd_pcm_runtime *runtime); | ||
43 | unsigned int mixer_channels; | ||
44 | u8 mute_fb_id; | ||
45 | u8 volume_fb_id; | ||
46 | }; | ||
47 | |||
48 | struct snd_oxfw { | ||
49 | struct snd_card *card; | ||
50 | struct fw_unit *unit; | ||
51 | const struct device_info *device_info; | ||
52 | struct mutex mutex; | ||
53 | struct cmp_connection in_conn; | ||
54 | struct amdtp_stream rx_stream; | ||
55 | bool mute; | ||
56 | s16 volume[6]; | ||
57 | s16 volume_min; | ||
58 | s16 volume_max; | ||
59 | }; | ||
60 | |||
61 | MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); | 23 | MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); |
62 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 24 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
63 | MODULE_LICENSE("GPL v2"); | 25 | MODULE_LICENSE("GPL v2"); |
@@ -180,14 +142,6 @@ static int oxfw_close(struct snd_pcm_substream *substream) | |||
180 | return 0; | 142 | return 0; |
181 | } | 143 | } |
182 | 144 | ||
183 | static void oxfw_stop_stream(struct snd_oxfw *oxfw) | ||
184 | { | ||
185 | if (amdtp_stream_running(&oxfw->rx_stream)) { | ||
186 | amdtp_stream_stop(&oxfw->rx_stream); | ||
187 | cmp_connection_break(&oxfw->in_conn); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static int oxfw_hw_params(struct snd_pcm_substream *substream, | 145 | static int oxfw_hw_params(struct snd_pcm_substream *substream, |
192 | struct snd_pcm_hw_params *hw_params) | 146 | struct snd_pcm_hw_params *hw_params) |
193 | { | 147 | { |
@@ -195,8 +149,8 @@ static int oxfw_hw_params(struct snd_pcm_substream *substream, | |||
195 | int err; | 149 | int err; |
196 | 150 | ||
197 | mutex_lock(&oxfw->mutex); | 151 | mutex_lock(&oxfw->mutex); |
198 | oxfw_stop_stream(oxfw); | 152 | |
199 | mutex_unlock(&oxfw->mutex); | 153 | snd_oxfw_stream_stop_simplex(oxfw); |
200 | 154 | ||
201 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, | 155 | err = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
202 | params_buffer_bytes(hw_params)); | 156 | params_buffer_bytes(hw_params)); |
@@ -223,6 +177,7 @@ static int oxfw_hw_params(struct snd_pcm_substream *substream, | |||
223 | err_buffer: | 177 | err_buffer: |
224 | snd_pcm_lib_free_vmalloc_buffer(substream); | 178 | snd_pcm_lib_free_vmalloc_buffer(substream); |
225 | error: | 179 | error: |
180 | mutex_unlock(&oxfw->mutex); | ||
226 | return err; | 181 | return err; |
227 | } | 182 | } |
228 | 183 | ||
@@ -231,7 +186,7 @@ static int oxfw_hw_free(struct snd_pcm_substream *substream) | |||
231 | struct snd_oxfw *oxfw = substream->private_data; | 186 | struct snd_oxfw *oxfw = substream->private_data; |
232 | 187 | ||
233 | mutex_lock(&oxfw->mutex); | 188 | mutex_lock(&oxfw->mutex); |
234 | oxfw_stop_stream(oxfw); | 189 | snd_oxfw_stream_stop_simplex(oxfw); |
235 | mutex_unlock(&oxfw->mutex); | 190 | mutex_unlock(&oxfw->mutex); |
236 | 191 | ||
237 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 192 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
@@ -244,33 +199,15 @@ static int oxfw_prepare(struct snd_pcm_substream *substream) | |||
244 | 199 | ||
245 | mutex_lock(&oxfw->mutex); | 200 | mutex_lock(&oxfw->mutex); |
246 | 201 | ||
247 | if (amdtp_streaming_error(&oxfw->rx_stream)) | 202 | snd_oxfw_stream_stop_simplex(oxfw); |
248 | oxfw_stop_stream(oxfw); | ||
249 | |||
250 | if (!amdtp_stream_running(&oxfw->rx_stream)) { | ||
251 | err = cmp_connection_establish(&oxfw->in_conn, | ||
252 | amdtp_stream_get_max_payload(&oxfw->rx_stream)); | ||
253 | if (err < 0) | ||
254 | goto err_mutex; | ||
255 | 203 | ||
256 | err = amdtp_stream_start(&oxfw->rx_stream, | 204 | err = snd_oxfw_stream_start_simplex(oxfw); |
257 | oxfw->in_conn.resources.channel, | 205 | if (err < 0) |
258 | oxfw->in_conn.speed); | 206 | goto end; |
259 | if (err < 0) | ||
260 | goto err_connection; | ||
261 | } | ||
262 | |||
263 | mutex_unlock(&oxfw->mutex); | ||
264 | 207 | ||
265 | amdtp_stream_pcm_prepare(&oxfw->rx_stream); | 208 | amdtp_stream_pcm_prepare(&oxfw->rx_stream); |
266 | 209 | end: | |
267 | return 0; | ||
268 | |||
269 | err_connection: | ||
270 | cmp_connection_break(&oxfw->in_conn); | ||
271 | err_mutex: | ||
272 | mutex_unlock(&oxfw->mutex); | 210 | mutex_unlock(&oxfw->mutex); |
273 | |||
274 | return err; | 211 | return err; |
275 | } | 212 | } |
276 | 213 | ||
@@ -615,9 +552,6 @@ static void oxfw_card_free(struct snd_card *card) | |||
615 | { | 552 | { |
616 | struct snd_oxfw *oxfw = card->private_data; | 553 | struct snd_oxfw *oxfw = card->private_data; |
617 | 554 | ||
618 | amdtp_stream_destroy(&oxfw->rx_stream); | ||
619 | cmp_connection_destroy(&oxfw->in_conn); | ||
620 | fw_unit_put(oxfw->unit); | ||
621 | mutex_destroy(&oxfw->mutex); | 555 | mutex_destroy(&oxfw->mutex); |
622 | } | 556 | } |
623 | 557 | ||
@@ -635,23 +569,13 @@ static int oxfw_probe(struct fw_unit *unit, | |||
635 | if (err < 0) | 569 | if (err < 0) |
636 | return err; | 570 | return err; |
637 | 571 | ||
572 | card->private_free = oxfw_card_free; | ||
638 | oxfw = card->private_data; | 573 | oxfw = card->private_data; |
639 | oxfw->card = card; | 574 | oxfw->card = card; |
640 | mutex_init(&oxfw->mutex); | 575 | mutex_init(&oxfw->mutex); |
641 | oxfw->unit = fw_unit_get(unit); | 576 | oxfw->unit = unit; |
642 | oxfw->device_info = (const struct device_info *)id->driver_data; | 577 | oxfw->device_info = (const struct device_info *)id->driver_data; |
643 | 578 | ||
644 | err = cmp_connection_init(&oxfw->in_conn, unit, CMP_INPUT, 0); | ||
645 | if (err < 0) | ||
646 | goto err_unit; | ||
647 | |||
648 | err = amdtp_stream_init(&oxfw->rx_stream, unit, AMDTP_OUT_STREAM, | ||
649 | CIP_NONBLOCKING); | ||
650 | if (err < 0) | ||
651 | goto err_connection; | ||
652 | |||
653 | card->private_free = oxfw_card_free; | ||
654 | |||
655 | strcpy(card->driver, oxfw->device_info->driver_name); | 579 | strcpy(card->driver, oxfw->device_info->driver_name); |
656 | strcpy(card->shortname, oxfw->device_info->short_name); | 580 | strcpy(card->shortname, oxfw->device_info->short_name); |
657 | firmware = oxfw_read_firmware_version(unit); | 581 | firmware = oxfw_read_firmware_version(unit); |
@@ -671,19 +595,18 @@ static int oxfw_probe(struct fw_unit *unit, | |||
671 | if (err < 0) | 595 | if (err < 0) |
672 | goto error; | 596 | goto error; |
673 | 597 | ||
674 | err = snd_card_register(card); | 598 | err = snd_oxfw_stream_init_simplex(oxfw); |
675 | if (err < 0) | 599 | if (err < 0) |
676 | goto error; | 600 | goto error; |
677 | 601 | ||
602 | err = snd_card_register(card); | ||
603 | if (err < 0) { | ||
604 | snd_oxfw_stream_destroy_simplex(oxfw); | ||
605 | goto error; | ||
606 | } | ||
678 | dev_set_drvdata(&unit->device, oxfw); | 607 | dev_set_drvdata(&unit->device, oxfw); |
679 | 608 | ||
680 | return 0; | 609 | return 0; |
681 | |||
682 | err_connection: | ||
683 | cmp_connection_destroy(&oxfw->in_conn); | ||
684 | err_unit: | ||
685 | fw_unit_put(oxfw->unit); | ||
686 | mutex_destroy(&oxfw->mutex); | ||
687 | error: | 610 | error: |
688 | snd_card_free(card); | 611 | snd_card_free(card); |
689 | return err; | 612 | return err; |
@@ -695,27 +618,18 @@ static void oxfw_bus_reset(struct fw_unit *unit) | |||
695 | 618 | ||
696 | fcp_bus_reset(oxfw->unit); | 619 | fcp_bus_reset(oxfw->unit); |
697 | 620 | ||
698 | if (cmp_connection_update(&oxfw->in_conn) < 0) { | 621 | mutex_lock(&oxfw->mutex); |
699 | amdtp_stream_pcm_abort(&oxfw->rx_stream); | 622 | snd_oxfw_stream_update_simplex(oxfw); |
700 | mutex_lock(&oxfw->mutex); | 623 | mutex_unlock(&oxfw->mutex); |
701 | oxfw_stop_stream(oxfw); | ||
702 | mutex_unlock(&oxfw->mutex); | ||
703 | return; | ||
704 | } | ||
705 | |||
706 | amdtp_stream_update(&oxfw->rx_stream); | ||
707 | } | 624 | } |
708 | 625 | ||
709 | static void oxfw_remove(struct fw_unit *unit) | 626 | static void oxfw_remove(struct fw_unit *unit) |
710 | { | 627 | { |
711 | struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); | 628 | struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); |
712 | 629 | ||
713 | amdtp_stream_pcm_abort(&oxfw->rx_stream); | ||
714 | snd_card_disconnect(oxfw->card); | 630 | snd_card_disconnect(oxfw->card); |
715 | 631 | ||
716 | mutex_lock(&oxfw->mutex); | 632 | snd_oxfw_stream_destroy_simplex(oxfw); |
717 | oxfw_stop_stream(oxfw); | ||
718 | mutex_unlock(&oxfw->mutex); | ||
719 | 633 | ||
720 | snd_card_free_when_closed(oxfw->card); | 634 | snd_card_free_when_closed(oxfw->card); |
721 | } | 635 | } |
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h new file mode 100644 index 000000000000..e5836e02b48c --- /dev/null +++ b/sound/firewire/oxfw/oxfw.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * oxfw.h - a part of driver for OXFW970/971 based devices | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * Licensed under the terms of the GNU General Public License, version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/device.h> | ||
9 | #include <linux/firewire.h> | ||
10 | #include <linux/firewire-constants.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/mod_devicetable.h> | ||
13 | #include <linux/mutex.h> | ||
14 | #include <linux/slab.h> | ||
15 | |||
16 | #include <sound/control.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/initval.h> | ||
19 | #include <sound/pcm.h> | ||
20 | #include <sound/pcm_params.h> | ||
21 | |||
22 | #include "../lib.h" | ||
23 | #include "../fcp.h" | ||
24 | #include "../packets-buffer.h" | ||
25 | #include "../iso-resources.h" | ||
26 | #include "../amdtp.h" | ||
27 | #include "../cmp.h" | ||
28 | |||
29 | struct device_info { | ||
30 | const char *driver_name; | ||
31 | const char *short_name; | ||
32 | const char *long_name; | ||
33 | int (*pcm_constraints)(struct snd_pcm_runtime *runtime); | ||
34 | unsigned int mixer_channels; | ||
35 | u8 mute_fb_id; | ||
36 | u8 volume_fb_id; | ||
37 | }; | ||
38 | |||
39 | struct snd_oxfw { | ||
40 | struct snd_card *card; | ||
41 | struct fw_unit *unit; | ||
42 | const struct device_info *device_info; | ||
43 | struct mutex mutex; | ||
44 | struct cmp_connection in_conn; | ||
45 | struct amdtp_stream rx_stream; | ||
46 | bool mute; | ||
47 | s16 volume[6]; | ||
48 | s16 volume_min; | ||
49 | s16 volume_max; | ||
50 | }; | ||
51 | |||
52 | int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw); | ||
53 | int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw); | ||
54 | void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw); | ||
55 | void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw); | ||
56 | void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw); | ||