diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/firewire/bebob/Makefile | 2 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.c | 15 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.h | 114 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob_command.c | 205 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob_stream.c | 874 |
5 files changed, 1208 insertions, 2 deletions
diff --git a/sound/firewire/bebob/Makefile b/sound/firewire/bebob/Makefile index c6f014188bbd..5cece62e30c0 100644 --- a/sound/firewire/bebob/Makefile +++ b/sound/firewire/bebob/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | snd-bebob-objs := bebob.o | 1 | snd-bebob-objs := bebob_command.o bebob_stream.o bebob.o |
2 | obj-m += snd-bebob.o | 2 | obj-m += snd-bebob.o |
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index b5644ab473c6..180284db84c9 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c | |||
@@ -158,9 +158,20 @@ bebob_probe(struct fw_unit *unit, | |||
158 | if (err < 0) | 158 | if (err < 0) |
159 | goto error; | 159 | goto error; |
160 | 160 | ||
161 | err = snd_card_register(card); | 161 | err = snd_bebob_stream_discover(bebob); |
162 | if (err < 0) | 162 | if (err < 0) |
163 | goto error; | 163 | goto error; |
164 | |||
165 | err = snd_bebob_stream_init_duplex(bebob); | ||
166 | if (err < 0) | ||
167 | goto error; | ||
168 | |||
169 | err = snd_card_register(card); | ||
170 | if (err < 0) { | ||
171 | snd_bebob_stream_destroy_duplex(bebob); | ||
172 | goto error; | ||
173 | } | ||
174 | |||
164 | dev_set_drvdata(&unit->device, bebob); | 175 | dev_set_drvdata(&unit->device, bebob); |
165 | end: | 176 | end: |
166 | mutex_unlock(&devices_mutex); | 177 | mutex_unlock(&devices_mutex); |
@@ -176,11 +187,13 @@ bebob_update(struct fw_unit *unit) | |||
176 | { | 187 | { |
177 | struct snd_bebob *bebob = dev_get_drvdata(&unit->device); | 188 | struct snd_bebob *bebob = dev_get_drvdata(&unit->device); |
178 | fcp_bus_reset(bebob->unit); | 189 | fcp_bus_reset(bebob->unit); |
190 | snd_bebob_stream_update_duplex(bebob); | ||
179 | } | 191 | } |
180 | 192 | ||
181 | static void bebob_remove(struct fw_unit *unit) | 193 | static void bebob_remove(struct fw_unit *unit) |
182 | { | 194 | { |
183 | struct snd_bebob *bebob = dev_get_drvdata(&unit->device); | 195 | struct snd_bebob *bebob = dev_get_drvdata(&unit->device); |
196 | snd_bebob_stream_destroy_duplex(bebob); | ||
184 | snd_card_disconnect(bebob->card); | 197 | snd_card_disconnect(bebob->card); |
185 | snd_card_free_when_closed(bebob->card); | 198 | snd_card_free_when_closed(bebob->card); |
186 | } | 199 | } |
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 862f756ec281..a195c16da41e 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h | |||
@@ -23,11 +23,25 @@ | |||
23 | 23 | ||
24 | #include "../lib.h" | 24 | #include "../lib.h" |
25 | #include "../fcp.h" | 25 | #include "../fcp.h" |
26 | #include "../packets-buffer.h" | ||
27 | #include "../iso-resources.h" | ||
28 | #include "../amdtp.h" | ||
29 | #include "../cmp.h" | ||
26 | 30 | ||
27 | /* basic register addresses on DM1000/DM1100/DM1500 */ | 31 | /* basic register addresses on DM1000/DM1100/DM1500 */ |
28 | #define BEBOB_ADDR_REG_INFO 0xffffc8020000 | 32 | #define BEBOB_ADDR_REG_INFO 0xffffc8020000 |
29 | #define BEBOB_ADDR_REG_REQ 0xffffc8021000 | 33 | #define BEBOB_ADDR_REG_REQ 0xffffc8021000 |
30 | 34 | ||
35 | struct snd_bebob; | ||
36 | |||
37 | #define SND_BEBOB_STRM_FMT_ENTRIES 7 | ||
38 | struct snd_bebob_stream_formation { | ||
39 | unsigned int pcm; | ||
40 | unsigned int midi; | ||
41 | }; | ||
42 | /* this is a lookup table for index of stream formations */ | ||
43 | extern const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES]; | ||
44 | |||
31 | struct snd_bebob { | 45 | struct snd_bebob { |
32 | struct snd_card *card; | 46 | struct snd_card *card; |
33 | struct fw_unit *unit; | 47 | struct fw_unit *unit; |
@@ -35,6 +49,24 @@ struct snd_bebob { | |||
35 | 49 | ||
36 | struct mutex mutex; | 50 | struct mutex mutex; |
37 | spinlock_t lock; | 51 | spinlock_t lock; |
52 | |||
53 | unsigned int midi_input_ports; | ||
54 | unsigned int midi_output_ports; | ||
55 | |||
56 | struct amdtp_stream *master; | ||
57 | struct amdtp_stream tx_stream; | ||
58 | struct amdtp_stream rx_stream; | ||
59 | struct cmp_connection out_conn; | ||
60 | struct cmp_connection in_conn; | ||
61 | atomic_t capture_substreams; | ||
62 | atomic_t playback_substreams; | ||
63 | |||
64 | struct snd_bebob_stream_formation | ||
65 | tx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES]; | ||
66 | struct snd_bebob_stream_formation | ||
67 | rx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES]; | ||
68 | |||
69 | int sync_input_plug; | ||
38 | }; | 70 | }; |
39 | 71 | ||
40 | static inline int | 72 | static inline int |
@@ -53,6 +85,88 @@ snd_bebob_read_quad(struct fw_unit *unit, u64 addr, u32 *buf) | |||
53 | (void *)buf, sizeof(u32), 0); | 85 | (void *)buf, sizeof(u32), 0); |
54 | } | 86 | } |
55 | 87 | ||
88 | /* | ||
89 | * AVC command extensions, AV/C Unit and Subunit, Revision 17 | ||
90 | * (Nov 2003, BridgeCo) | ||
91 | */ | ||
92 | #define AVC_BRIDGECO_ADDR_BYTES 6 | ||
93 | enum avc_bridgeco_plug_dir { | ||
94 | AVC_BRIDGECO_PLUG_DIR_IN = 0x00, | ||
95 | AVC_BRIDGECO_PLUG_DIR_OUT = 0x01 | ||
96 | }; | ||
97 | enum avc_bridgeco_plug_mode { | ||
98 | AVC_BRIDGECO_PLUG_MODE_UNIT = 0x00, | ||
99 | AVC_BRIDGECO_PLUG_MODE_SUBUNIT = 0x01, | ||
100 | AVC_BRIDGECO_PLUG_MODE_FUNCTION_BLOCK = 0x02 | ||
101 | }; | ||
102 | enum avc_bridgeco_plug_unit { | ||
103 | AVC_BRIDGECO_PLUG_UNIT_ISOC = 0x00, | ||
104 | AVC_BRIDGECO_PLUG_UNIT_EXT = 0x01, | ||
105 | AVC_BRIDGECO_PLUG_UNIT_ASYNC = 0x02 | ||
106 | }; | ||
107 | enum avc_bridgeco_plug_type { | ||
108 | AVC_BRIDGECO_PLUG_TYPE_ISOC = 0x00, | ||
109 | AVC_BRIDGECO_PLUG_TYPE_ASYNC = 0x01, | ||
110 | AVC_BRIDGECO_PLUG_TYPE_MIDI = 0x02, | ||
111 | AVC_BRIDGECO_PLUG_TYPE_SYNC = 0x03, | ||
112 | AVC_BRIDGECO_PLUG_TYPE_ANA = 0x04, | ||
113 | AVC_BRIDGECO_PLUG_TYPE_DIG = 0x05 | ||
114 | }; | ||
115 | static inline void | ||
116 | avc_bridgeco_fill_unit_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES], | ||
117 | enum avc_bridgeco_plug_dir dir, | ||
118 | enum avc_bridgeco_plug_unit unit, | ||
119 | unsigned int pid) | ||
120 | { | ||
121 | buf[0] = 0xff; /* Unit */ | ||
122 | buf[1] = dir; | ||
123 | buf[2] = AVC_BRIDGECO_PLUG_MODE_UNIT; | ||
124 | buf[3] = unit; | ||
125 | buf[4] = 0xff & pid; | ||
126 | buf[5] = 0xff; /* reserved */ | ||
127 | } | ||
128 | static inline void | ||
129 | avc_bridgeco_fill_msu_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES], | ||
130 | enum avc_bridgeco_plug_dir dir, | ||
131 | unsigned int pid) | ||
132 | { | ||
133 | buf[0] = 0x60; /* Music subunit */ | ||
134 | buf[1] = dir; | ||
135 | buf[2] = AVC_BRIDGECO_PLUG_MODE_SUBUNIT; | ||
136 | buf[3] = 0xff & pid; | ||
137 | buf[4] = 0xff; /* reserved */ | ||
138 | buf[5] = 0xff; /* reserved */ | ||
139 | } | ||
140 | int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, | ||
141 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], | ||
142 | u8 *buf, unsigned int len); | ||
143 | int avc_bridgeco_get_plug_type(struct fw_unit *unit, | ||
144 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], | ||
145 | enum avc_bridgeco_plug_type *type); | ||
146 | int avc_bridgeco_get_plug_section_type(struct fw_unit *unit, | ||
147 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], | ||
148 | unsigned int id, u8 *type); | ||
149 | int avc_bridgeco_get_plug_input(struct fw_unit *unit, | ||
150 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], | ||
151 | u8 input[7]); | ||
152 | int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit, | ||
153 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf, | ||
154 | unsigned int *len, unsigned int eid); | ||
155 | |||
156 | /* for AMDTP streaming */ | ||
157 | int snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *rate); | ||
158 | int snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate); | ||
159 | int snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, | ||
160 | bool *internal); | ||
161 | int snd_bebob_stream_discover(struct snd_bebob *bebob); | ||
162 | int snd_bebob_stream_map(struct snd_bebob *bebob, | ||
163 | struct amdtp_stream *stream); | ||
164 | int snd_bebob_stream_init_duplex(struct snd_bebob *bebob); | ||
165 | int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate); | ||
166 | void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob); | ||
167 | void snd_bebob_stream_update_duplex(struct snd_bebob *bebob); | ||
168 | void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob); | ||
169 | |||
56 | #define SND_BEBOB_DEV_ENTRY(vendor, model) \ | 170 | #define SND_BEBOB_DEV_ENTRY(vendor, model) \ |
57 | { \ | 171 | { \ |
58 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ | 172 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ |
diff --git a/sound/firewire/bebob/bebob_command.c b/sound/firewire/bebob/bebob_command.c new file mode 100644 index 000000000000..6a017951a888 --- /dev/null +++ b/sound/firewire/bebob/bebob_command.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * bebob_command.c - driver for BeBoB based devices | ||
3 | * | ||
4 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
5 | * | ||
6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "./bebob.h" | ||
10 | |||
11 | static inline void | ||
12 | avc_bridgeco_fill_extension_addr(u8 *buf, u8 *addr) | ||
13 | { | ||
14 | buf[1] = addr[0]; | ||
15 | memcpy(buf + 4, addr + 1, 5); | ||
16 | } | ||
17 | |||
18 | static inline void | ||
19 | avc_bridgeco_fill_plug_info_extension_command(u8 *buf, u8 *addr, | ||
20 | unsigned int itype) | ||
21 | { | ||
22 | buf[0] = 0x01; /* AV/C STATUS */ | ||
23 | buf[2] = 0x02; /* AV/C GENERAL PLUG INFO */ | ||
24 | buf[3] = 0xc0; /* BridgeCo extension */ | ||
25 | avc_bridgeco_fill_extension_addr(buf, addr); | ||
26 | buf[9] = itype; /* info type */ | ||
27 | } | ||
28 | |||
29 | int avc_bridgeco_get_plug_type(struct fw_unit *unit, | ||
30 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], | ||
31 | enum avc_bridgeco_plug_type *type) | ||
32 | { | ||
33 | u8 *buf; | ||
34 | int err; | ||
35 | |||
36 | buf = kzalloc(12, GFP_KERNEL); | ||
37 | if (buf == NULL) | ||
38 | return -ENOMEM; | ||
39 | |||
40 | /* Info type is 'plug type'. */ | ||
41 | avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x00); | ||
42 | |||
43 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, | ||
44 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | ||
45 | BIT(6) | BIT(7) | BIT(9)); | ||
46 | if ((err >= 0) && (err < 8)) | ||
47 | err = -EIO; | ||
48 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | ||
49 | err = -ENOSYS; | ||
50 | else if (buf[0] == 0x0a) /* REJECTED */ | ||
51 | err = -EINVAL; | ||
52 | else if (buf[0] == 0x0b) /* IN TRANSITION */ | ||
53 | err = -EAGAIN; | ||
54 | if (err < 0) | ||
55 | goto end; | ||
56 | |||
57 | *type = buf[10]; | ||
58 | err = 0; | ||
59 | end: | ||
60 | kfree(buf); | ||
61 | return err; | ||
62 | } | ||
63 | |||
64 | int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, | ||
65 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], | ||
66 | u8 *buf, unsigned int len) | ||
67 | { | ||
68 | int err; | ||
69 | |||
70 | /* Info type is 'channel position'. */ | ||
71 | avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x03); | ||
72 | |||
73 | err = fcp_avc_transaction(unit, buf, 12, buf, 256, | ||
74 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | | ||
75 | BIT(5) | BIT(6) | BIT(7) | BIT(9)); | ||
76 | if ((err >= 0) && (err < 8)) | ||
77 | err = -EIO; | ||
78 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | ||
79 | err = -ENOSYS; | ||
80 | else if (buf[0] == 0x0a) /* REJECTED */ | ||
81 | err = -EINVAL; | ||
82 | else if (buf[0] == 0x0b) /* IN TRANSITION */ | ||
83 | err = -EAGAIN; | ||
84 | if (err < 0) | ||
85 | goto end; | ||
86 | |||
87 | /* Pick up specific data. */ | ||
88 | memmove(buf, buf + 10, err - 10); | ||
89 | err = 0; | ||
90 | end: | ||
91 | return err; | ||
92 | } | ||
93 | |||
94 | int avc_bridgeco_get_plug_section_type(struct fw_unit *unit, | ||
95 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], | ||
96 | unsigned int id, u8 *type) | ||
97 | { | ||
98 | u8 *buf; | ||
99 | int err; | ||
100 | |||
101 | /* section info includes charactors but this module don't need it */ | ||
102 | buf = kzalloc(12, GFP_KERNEL); | ||
103 | if (buf == NULL) | ||
104 | return -ENOMEM; | ||
105 | |||
106 | /* Info type is 'section info'. */ | ||
107 | avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x07); | ||
108 | buf[10] = 0xff & ++id; /* section id */ | ||
109 | |||
110 | err = fcp_avc_transaction(unit, buf, 12, buf, 12, | ||
111 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | ||
112 | BIT(6) | BIT(7) | BIT(9) | BIT(10)); | ||
113 | if ((err >= 0) && (err < 8)) | ||
114 | err = -EIO; | ||
115 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | ||
116 | err = -ENOSYS; | ||
117 | else if (buf[0] == 0x0a) /* REJECTED */ | ||
118 | err = -EINVAL; | ||
119 | else if (buf[0] == 0x0b) /* IN TRANSITION */ | ||
120 | err = -EAGAIN; | ||
121 | if (err < 0) | ||
122 | goto end; | ||
123 | |||
124 | *type = buf[11]; | ||
125 | err = 0; | ||
126 | end: | ||
127 | kfree(buf); | ||
128 | return err; | ||
129 | } | ||
130 | |||
131 | int avc_bridgeco_get_plug_input(struct fw_unit *unit, | ||
132 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 input[7]) | ||
133 | { | ||
134 | int err; | ||
135 | u8 *buf; | ||
136 | |||
137 | buf = kzalloc(18, GFP_KERNEL); | ||
138 | if (buf == NULL) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | /* Info type is 'plug input'. */ | ||
142 | avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x05); | ||
143 | |||
144 | err = fcp_avc_transaction(unit, buf, 16, buf, 16, | ||
145 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | ||
146 | BIT(6) | BIT(7)); | ||
147 | if ((err >= 0) && (err < 8)) | ||
148 | err = -EIO; | ||
149 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | ||
150 | err = -ENOSYS; | ||
151 | else if (buf[0] == 0x0a) /* REJECTED */ | ||
152 | err = -EINVAL; | ||
153 | else if (buf[0] == 0x0b) /* IN TRANSITION */ | ||
154 | err = -EAGAIN; | ||
155 | if (err < 0) | ||
156 | goto end; | ||
157 | |||
158 | memcpy(input, buf + 10, 5); | ||
159 | err = 0; | ||
160 | end: | ||
161 | kfree(buf); | ||
162 | return err; | ||
163 | } | ||
164 | |||
165 | int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit, | ||
166 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf, | ||
167 | unsigned int *len, unsigned int eid) | ||
168 | { | ||
169 | int err; | ||
170 | |||
171 | /* check given buffer */ | ||
172 | if ((buf == NULL) || (*len < 12)) { | ||
173 | err = -EINVAL; | ||
174 | goto end; | ||
175 | } | ||
176 | |||
177 | buf[0] = 0x01; /* AV/C STATUS */ | ||
178 | buf[2] = 0x2f; /* AV/C STREAM FORMAT SUPPORT */ | ||
179 | buf[3] = 0xc1; /* Bridgeco extension - List Request */ | ||
180 | avc_bridgeco_fill_extension_addr(buf, addr); | ||
181 | buf[10] = 0xff & eid; /* Entry ID */ | ||
182 | |||
183 | err = fcp_avc_transaction(unit, buf, 12, buf, *len, | ||
184 | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | | ||
185 | BIT(6) | BIT(7) | BIT(10)); | ||
186 | if ((err >= 0) && (err < 12)) | ||
187 | err = -EIO; | ||
188 | else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ | ||
189 | err = -ENOSYS; | ||
190 | else if (buf[0] == 0x0a) /* REJECTED */ | ||
191 | err = -EINVAL; | ||
192 | else if (buf[0] == 0x0b) /* IN TRANSITION */ | ||
193 | err = -EAGAIN; | ||
194 | else if (buf[10] != eid) | ||
195 | err = -EIO; | ||
196 | if (err < 0) | ||
197 | goto end; | ||
198 | |||
199 | /* Pick up 'stream format info'. */ | ||
200 | memmove(buf, buf + 11, err - 11); | ||
201 | *len = err - 11; | ||
202 | err = 0; | ||
203 | end: | ||
204 | return err; | ||
205 | } | ||
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c new file mode 100644 index 000000000000..c868c17c6fc4 --- /dev/null +++ b/sound/firewire/bebob/bebob_stream.c | |||
@@ -0,0 +1,874 @@ | |||
1 | /* | ||
2 | * bebob_stream.c - a part of driver for BeBoB based devices | ||
3 | * | ||
4 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
5 | * | ||
6 | * Licensed under the terms of the GNU General Public License, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "./bebob.h" | ||
10 | |||
11 | #define CALLBACK_TIMEOUT 1000 | ||
12 | |||
13 | /* | ||
14 | * NOTE; | ||
15 | * For BeBoB streams, Both of input and output CMP connection are important. | ||
16 | * | ||
17 | * For most devices, each CMP connection starts to transmit/receive a | ||
18 | * corresponding stream. But for a few devices, both of CMP connection needs | ||
19 | * to start transmitting stream. An example is 'M-Audio Firewire 410'. | ||
20 | */ | ||
21 | |||
22 | /* 128 is an arbitrary length but it seems to be enough */ | ||
23 | #define FORMAT_MAXIMUM_LENGTH 128 | ||
24 | |||
25 | const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES] = { | ||
26 | [0] = 32000, | ||
27 | [1] = 44100, | ||
28 | [2] = 48000, | ||
29 | [3] = 88200, | ||
30 | [4] = 96000, | ||
31 | [5] = 176400, | ||
32 | [6] = 192000, | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * See: Table 51: Extended Stream Format Info ‘Sampling Frequency’ | ||
37 | * in Additional AVC commands (Nov 2003, BridgeCo) | ||
38 | */ | ||
39 | static const unsigned int bridgeco_freq_table[] = { | ||
40 | [0] = 0x02, | ||
41 | [1] = 0x03, | ||
42 | [2] = 0x04, | ||
43 | [3] = 0x0a, | ||
44 | [4] = 0x05, | ||
45 | [5] = 0x06, | ||
46 | [6] = 0x07, | ||
47 | }; | ||
48 | |||
49 | static unsigned int | ||
50 | get_formation_index(unsigned int rate) | ||
51 | { | ||
52 | unsigned int i; | ||
53 | |||
54 | for (i = 0; i < ARRAY_SIZE(snd_bebob_rate_table); i++) { | ||
55 | if (snd_bebob_rate_table[i] == rate) | ||
56 | return i; | ||
57 | } | ||
58 | return -EINVAL; | ||
59 | } | ||
60 | |||
61 | int | ||
62 | snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *curr_rate) | ||
63 | { | ||
64 | unsigned int tx_rate, rx_rate, trials; | ||
65 | int err; | ||
66 | |||
67 | trials = 0; | ||
68 | do { | ||
69 | err = avc_general_get_sig_fmt(bebob->unit, &tx_rate, | ||
70 | AVC_GENERAL_PLUG_DIR_OUT, 0); | ||
71 | } while (err == -EAGAIN && ++trials < 3); | ||
72 | if (err < 0) | ||
73 | goto end; | ||
74 | |||
75 | trials = 0; | ||
76 | do { | ||
77 | err = avc_general_get_sig_fmt(bebob->unit, &rx_rate, | ||
78 | AVC_GENERAL_PLUG_DIR_IN, 0); | ||
79 | } while (err == -EAGAIN && ++trials < 3); | ||
80 | if (err < 0) | ||
81 | goto end; | ||
82 | |||
83 | *curr_rate = rx_rate; | ||
84 | if (rx_rate == tx_rate) | ||
85 | goto end; | ||
86 | |||
87 | /* synchronize receive stream rate to transmit stream rate */ | ||
88 | err = avc_general_set_sig_fmt(bebob->unit, rx_rate, | ||
89 | AVC_GENERAL_PLUG_DIR_IN, 0); | ||
90 | end: | ||
91 | return err; | ||
92 | } | ||
93 | |||
94 | int | ||
95 | snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate) | ||
96 | { | ||
97 | int err; | ||
98 | |||
99 | err = avc_general_set_sig_fmt(bebob->unit, rate, | ||
100 | AVC_GENERAL_PLUG_DIR_OUT, 0); | ||
101 | if (err < 0) | ||
102 | goto end; | ||
103 | |||
104 | err = avc_general_set_sig_fmt(bebob->unit, rate, | ||
105 | AVC_GENERAL_PLUG_DIR_IN, 0); | ||
106 | if (err < 0) | ||
107 | goto end; | ||
108 | |||
109 | /* | ||
110 | * Some devices need a bit time for transition. | ||
111 | * 300msec is got by some experiments. | ||
112 | */ | ||
113 | msleep(300); | ||
114 | end: | ||
115 | return err; | ||
116 | } | ||
117 | |||
118 | int | ||
119 | snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal) | ||
120 | { | ||
121 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7]; | ||
122 | int err = 0; | ||
123 | |||
124 | *internal = false; | ||
125 | |||
126 | /* | ||
127 | * 1.The device don't support to switch source of clock then assumed | ||
128 | * to use internal clock always | ||
129 | */ | ||
130 | if (bebob->sync_input_plug < 0) { | ||
131 | *internal = true; | ||
132 | goto end; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * 2.The device supports to switch source of clock by an usual way. | ||
137 | * Let's check input for 'Music Sub Unit Sync Input' plug. | ||
138 | */ | ||
139 | avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, | ||
140 | bebob->sync_input_plug); | ||
141 | err = avc_bridgeco_get_plug_input(bebob->unit, addr, input); | ||
142 | if (err < 0) { | ||
143 | dev_err(&bebob->unit->device, | ||
144 | "fail to get an input for MSU in plug %d: %d\n", | ||
145 | bebob->sync_input_plug, err); | ||
146 | goto end; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * If there are no input plugs, all of fields are 0xff. | ||
151 | * Here check the first field. This field is used for direction. | ||
152 | */ | ||
153 | if (input[0] == 0xff) { | ||
154 | *internal = true; | ||
155 | goto end; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * If source of clock is internal CSR, Music Sub Unit Sync Input is | ||
160 | * a destination of Music Sub Unit Sync Output. | ||
161 | */ | ||
162 | *internal = ((input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) && | ||
163 | (input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT) && | ||
164 | (input[2] == 0x0c) && | ||
165 | (input[3] == 0x00)); | ||
166 | end: | ||
167 | return err; | ||
168 | } | ||
169 | |||
170 | static unsigned int | ||
171 | map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s) | ||
172 | { | ||
173 | unsigned int sec, sections, ch, channels; | ||
174 | unsigned int pcm, midi, location; | ||
175 | unsigned int stm_pos, sec_loc, pos; | ||
176 | u8 *buf, addr[AVC_BRIDGECO_ADDR_BYTES], type; | ||
177 | enum avc_bridgeco_plug_dir dir; | ||
178 | int err; | ||
179 | |||
180 | /* | ||
181 | * The length of return value of this command cannot be expected. Here | ||
182 | * use the maximum length of FCP. | ||
183 | */ | ||
184 | buf = kzalloc(256, GFP_KERNEL); | ||
185 | if (buf == NULL) | ||
186 | return -ENOMEM; | ||
187 | |||
188 | if (s == &bebob->tx_stream) | ||
189 | dir = AVC_BRIDGECO_PLUG_DIR_OUT; | ||
190 | else | ||
191 | dir = AVC_BRIDGECO_PLUG_DIR_IN; | ||
192 | |||
193 | avc_bridgeco_fill_unit_addr(addr, dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); | ||
194 | err = avc_bridgeco_get_plug_ch_pos(bebob->unit, addr, buf, 256); | ||
195 | if (err < 0) { | ||
196 | dev_err(&bebob->unit->device, | ||
197 | "fail to get channel position for isoc %s plug 0: %d\n", | ||
198 | (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : "out", | ||
199 | err); | ||
200 | goto end; | ||
201 | } | ||
202 | pos = 0; | ||
203 | |||
204 | /* positions in I/O buffer */ | ||
205 | pcm = 0; | ||
206 | midi = 0; | ||
207 | |||
208 | /* the number of sections in AMDTP packet */ | ||
209 | sections = buf[pos++]; | ||
210 | |||
211 | for (sec = 0; sec < sections; sec++) { | ||
212 | /* type of this section */ | ||
213 | avc_bridgeco_fill_unit_addr(addr, dir, | ||
214 | AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); | ||
215 | err = avc_bridgeco_get_plug_section_type(bebob->unit, addr, | ||
216 | sec, &type); | ||
217 | if (err < 0) { | ||
218 | dev_err(&bebob->unit->device, | ||
219 | "fail to get section type for isoc %s plug 0: %d\n", | ||
220 | (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : | ||
221 | "out", | ||
222 | err); | ||
223 | goto end; | ||
224 | } | ||
225 | /* NoType */ | ||
226 | if (type == 0xff) { | ||
227 | err = -ENOSYS; | ||
228 | goto end; | ||
229 | } | ||
230 | |||
231 | /* the number of channels in this section */ | ||
232 | channels = buf[pos++]; | ||
233 | |||
234 | for (ch = 0; ch < channels; ch++) { | ||
235 | /* position of this channel in AMDTP packet */ | ||
236 | stm_pos = buf[pos++] - 1; | ||
237 | /* location of this channel in this section */ | ||
238 | sec_loc = buf[pos++] - 1; | ||
239 | |||
240 | switch (type) { | ||
241 | /* for MIDI conformant data channel */ | ||
242 | case 0x0a: | ||
243 | /* AMDTP_MAX_CHANNELS_FOR_MIDI is 1. */ | ||
244 | if ((midi > 0) && (stm_pos != midi)) { | ||
245 | err = -ENOSYS; | ||
246 | goto end; | ||
247 | } | ||
248 | s->midi_position = stm_pos; | ||
249 | midi = stm_pos; | ||
250 | break; | ||
251 | /* for PCM data channel */ | ||
252 | case 0x01: /* Headphone */ | ||
253 | case 0x02: /* Microphone */ | ||
254 | case 0x03: /* Line */ | ||
255 | case 0x04: /* SPDIF */ | ||
256 | case 0x05: /* ADAT */ | ||
257 | case 0x06: /* TDIF */ | ||
258 | case 0x07: /* MADI */ | ||
259 | /* for undefined/changeable signal */ | ||
260 | case 0x08: /* Analog */ | ||
261 | case 0x09: /* Digital */ | ||
262 | default: | ||
263 | location = pcm + sec_loc; | ||
264 | if (location >= AMDTP_MAX_CHANNELS_FOR_PCM) { | ||
265 | err = -ENOSYS; | ||
266 | goto end; | ||
267 | } | ||
268 | s->pcm_positions[location] = stm_pos; | ||
269 | break; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | if (type != 0x0a) | ||
274 | pcm += channels; | ||
275 | else | ||
276 | midi += channels; | ||
277 | } | ||
278 | end: | ||
279 | kfree(buf); | ||
280 | return err; | ||
281 | } | ||
282 | |||
283 | static int | ||
284 | init_both_connections(struct snd_bebob *bebob) | ||
285 | { | ||
286 | int err; | ||
287 | |||
288 | err = cmp_connection_init(&bebob->in_conn, | ||
289 | bebob->unit, CMP_INPUT, 0); | ||
290 | if (err < 0) | ||
291 | goto end; | ||
292 | |||
293 | err = cmp_connection_init(&bebob->out_conn, | ||
294 | bebob->unit, CMP_OUTPUT, 0); | ||
295 | if (err < 0) | ||
296 | cmp_connection_destroy(&bebob->in_conn); | ||
297 | end: | ||
298 | return err; | ||
299 | } | ||
300 | |||
301 | static int | ||
302 | check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s) | ||
303 | { | ||
304 | struct cmp_connection *conn; | ||
305 | bool used; | ||
306 | int err; | ||
307 | |||
308 | if (s == &bebob->tx_stream) | ||
309 | conn = &bebob->out_conn; | ||
310 | else | ||
311 | conn = &bebob->in_conn; | ||
312 | |||
313 | err = cmp_connection_check_used(conn, &used); | ||
314 | if ((err >= 0) && used && !amdtp_stream_running(s)) { | ||
315 | dev_err(&bebob->unit->device, | ||
316 | "Connection established by others: %cPCR[%d]\n", | ||
317 | (conn->direction == CMP_OUTPUT) ? 'o' : 'i', | ||
318 | conn->pcr_index); | ||
319 | err = -EBUSY; | ||
320 | } | ||
321 | |||
322 | return err; | ||
323 | } | ||
324 | |||
325 | static int | ||
326 | make_both_connections(struct snd_bebob *bebob, unsigned int rate) | ||
327 | { | ||
328 | int index, pcm_channels, midi_channels, err; | ||
329 | |||
330 | /* confirm params for both streams */ | ||
331 | index = get_formation_index(rate); | ||
332 | pcm_channels = bebob->tx_stream_formations[index].pcm; | ||
333 | midi_channels = bebob->tx_stream_formations[index].midi; | ||
334 | amdtp_stream_set_parameters(&bebob->tx_stream, | ||
335 | rate, pcm_channels, midi_channels * 8); | ||
336 | pcm_channels = bebob->rx_stream_formations[index].pcm; | ||
337 | midi_channels = bebob->rx_stream_formations[index].midi; | ||
338 | amdtp_stream_set_parameters(&bebob->rx_stream, | ||
339 | rate, pcm_channels, midi_channels * 8); | ||
340 | |||
341 | /* establish connections for both streams */ | ||
342 | err = cmp_connection_establish(&bebob->out_conn, | ||
343 | amdtp_stream_get_max_payload(&bebob->tx_stream)); | ||
344 | if (err < 0) | ||
345 | goto end; | ||
346 | err = cmp_connection_establish(&bebob->in_conn, | ||
347 | amdtp_stream_get_max_payload(&bebob->rx_stream)); | ||
348 | if (err < 0) | ||
349 | cmp_connection_break(&bebob->out_conn); | ||
350 | end: | ||
351 | return err; | ||
352 | } | ||
353 | |||
354 | static void | ||
355 | break_both_connections(struct snd_bebob *bebob) | ||
356 | { | ||
357 | cmp_connection_break(&bebob->in_conn); | ||
358 | cmp_connection_break(&bebob->out_conn); | ||
359 | } | ||
360 | |||
361 | static void | ||
362 | destroy_both_connections(struct snd_bebob *bebob) | ||
363 | { | ||
364 | break_both_connections(bebob); | ||
365 | |||
366 | cmp_connection_destroy(&bebob->in_conn); | ||
367 | cmp_connection_destroy(&bebob->out_conn); | ||
368 | } | ||
369 | |||
370 | static int | ||
371 | get_sync_mode(struct snd_bebob *bebob, enum cip_flags *sync_mode) | ||
372 | { | ||
373 | /* currently this module doesn't support SYT-Match mode */ | ||
374 | *sync_mode = CIP_SYNC_TO_DEVICE; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int | ||
379 | start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream, | ||
380 | unsigned int rate) | ||
381 | { | ||
382 | struct cmp_connection *conn; | ||
383 | int err = 0; | ||
384 | |||
385 | if (stream == &bebob->rx_stream) | ||
386 | conn = &bebob->in_conn; | ||
387 | else | ||
388 | conn = &bebob->out_conn; | ||
389 | |||
390 | /* channel mapping */ | ||
391 | err = map_data_channels(bebob, stream); | ||
392 | if (err < 0) | ||
393 | goto end; | ||
394 | |||
395 | /* start amdtp stream */ | ||
396 | err = amdtp_stream_start(stream, | ||
397 | conn->resources.channel, | ||
398 | conn->speed); | ||
399 | end: | ||
400 | return err; | ||
401 | } | ||
402 | |||
403 | int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) | ||
404 | { | ||
405 | int err; | ||
406 | |||
407 | err = init_both_connections(bebob); | ||
408 | if (err < 0) | ||
409 | goto end; | ||
410 | |||
411 | err = amdtp_stream_init(&bebob->tx_stream, bebob->unit, | ||
412 | AMDTP_IN_STREAM, CIP_BLOCKING); | ||
413 | if (err < 0) { | ||
414 | amdtp_stream_destroy(&bebob->tx_stream); | ||
415 | destroy_both_connections(bebob); | ||
416 | goto end; | ||
417 | } | ||
418 | |||
419 | err = amdtp_stream_init(&bebob->rx_stream, bebob->unit, | ||
420 | AMDTP_OUT_STREAM, CIP_BLOCKING); | ||
421 | if (err < 0) { | ||
422 | amdtp_stream_destroy(&bebob->tx_stream); | ||
423 | amdtp_stream_destroy(&bebob->rx_stream); | ||
424 | destroy_both_connections(bebob); | ||
425 | } | ||
426 | end: | ||
427 | return err; | ||
428 | } | ||
429 | |||
430 | int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate) | ||
431 | { | ||
432 | struct amdtp_stream *master, *slave; | ||
433 | atomic_t *slave_substreams; | ||
434 | enum cip_flags sync_mode; | ||
435 | unsigned int curr_rate; | ||
436 | int err = 0; | ||
437 | |||
438 | mutex_lock(&bebob->mutex); | ||
439 | |||
440 | /* Need no substreams */ | ||
441 | if (atomic_read(&bebob->playback_substreams) == 0 && | ||
442 | atomic_read(&bebob->capture_substreams) == 0) | ||
443 | goto end; | ||
444 | |||
445 | err = get_sync_mode(bebob, &sync_mode); | ||
446 | if (err < 0) | ||
447 | goto end; | ||
448 | if (sync_mode == CIP_SYNC_TO_DEVICE) { | ||
449 | master = &bebob->tx_stream; | ||
450 | slave = &bebob->rx_stream; | ||
451 | slave_substreams = &bebob->playback_substreams; | ||
452 | } else { | ||
453 | master = &bebob->rx_stream; | ||
454 | slave = &bebob->tx_stream; | ||
455 | slave_substreams = &bebob->capture_substreams; | ||
456 | } | ||
457 | |||
458 | /* | ||
459 | * Considering JACK/FFADO streaming: | ||
460 | * TODO: This can be removed hwdep functionality becomes popular. | ||
461 | */ | ||
462 | err = check_connection_used_by_others(bebob, master); | ||
463 | if (err < 0) | ||
464 | goto end; | ||
465 | |||
466 | /* packet queueing error */ | ||
467 | if (amdtp_streaming_error(master)) { | ||
468 | amdtp_stream_stop(master); | ||
469 | amdtp_stream_stop(slave); | ||
470 | } | ||
471 | if (amdtp_streaming_error(slave)) | ||
472 | amdtp_stream_stop(slave); | ||
473 | |||
474 | /* stop streams if rate is different */ | ||
475 | err = snd_bebob_stream_get_rate(bebob, &curr_rate); | ||
476 | if (err < 0) { | ||
477 | dev_err(&bebob->unit->device, | ||
478 | "fail to get sampling rate: %d\n", err); | ||
479 | goto end; | ||
480 | } | ||
481 | if (rate == 0) | ||
482 | rate = curr_rate; | ||
483 | if (rate != curr_rate) { | ||
484 | amdtp_stream_stop(master); | ||
485 | amdtp_stream_stop(slave); | ||
486 | break_both_connections(bebob); | ||
487 | } | ||
488 | |||
489 | /* master should be always running */ | ||
490 | if (!amdtp_stream_running(master)) { | ||
491 | amdtp_stream_set_sync(sync_mode, master, slave); | ||
492 | bebob->master = master; | ||
493 | |||
494 | /* | ||
495 | * NOTE: | ||
496 | * If establishing connections at first, Yamaha GO46 | ||
497 | * (and maybe Terratec X24) don't generate sound. | ||
498 | */ | ||
499 | err = snd_bebob_stream_set_rate(bebob, rate); | ||
500 | if (err < 0) { | ||
501 | dev_err(&bebob->unit->device, | ||
502 | "fail to set sampling rate: %d\n", | ||
503 | err); | ||
504 | goto end; | ||
505 | } | ||
506 | |||
507 | err = make_both_connections(bebob, rate); | ||
508 | if (err < 0) | ||
509 | goto end; | ||
510 | |||
511 | err = start_stream(bebob, master, rate); | ||
512 | if (err < 0) { | ||
513 | dev_err(&bebob->unit->device, | ||
514 | "fail to run AMDTP master stream:%d\n", err); | ||
515 | break_both_connections(bebob); | ||
516 | goto end; | ||
517 | } | ||
518 | |||
519 | /* wait first callback */ | ||
520 | if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT)) { | ||
521 | amdtp_stream_stop(master); | ||
522 | break_both_connections(bebob); | ||
523 | err = -ETIMEDOUT; | ||
524 | goto end; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | /* start slave if needed */ | ||
529 | if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) { | ||
530 | err = start_stream(bebob, slave, rate); | ||
531 | if (err < 0) { | ||
532 | dev_err(&bebob->unit->device, | ||
533 | "fail to run AMDTP slave stream:%d\n", err); | ||
534 | amdtp_stream_stop(master); | ||
535 | break_both_connections(bebob); | ||
536 | goto end; | ||
537 | } | ||
538 | |||
539 | /* wait first callback */ | ||
540 | if (!amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) { | ||
541 | amdtp_stream_stop(slave); | ||
542 | amdtp_stream_stop(master); | ||
543 | break_both_connections(bebob); | ||
544 | err = -ETIMEDOUT; | ||
545 | } | ||
546 | } | ||
547 | end: | ||
548 | mutex_unlock(&bebob->mutex); | ||
549 | return err; | ||
550 | } | ||
551 | |||
552 | void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) | ||
553 | { | ||
554 | struct amdtp_stream *master, *slave; | ||
555 | atomic_t *master_substreams, *slave_substreams; | ||
556 | |||
557 | mutex_lock(&bebob->mutex); | ||
558 | |||
559 | if (bebob->master == &bebob->rx_stream) { | ||
560 | slave = &bebob->tx_stream; | ||
561 | master = &bebob->rx_stream; | ||
562 | slave_substreams = &bebob->capture_substreams; | ||
563 | master_substreams = &bebob->playback_substreams; | ||
564 | } else { | ||
565 | slave = &bebob->rx_stream; | ||
566 | master = &bebob->tx_stream; | ||
567 | slave_substreams = &bebob->playback_substreams; | ||
568 | master_substreams = &bebob->capture_substreams; | ||
569 | } | ||
570 | |||
571 | if (atomic_read(slave_substreams) == 0) { | ||
572 | amdtp_stream_pcm_abort(slave); | ||
573 | amdtp_stream_stop(slave); | ||
574 | |||
575 | if (atomic_read(master_substreams) == 0) { | ||
576 | amdtp_stream_pcm_abort(master); | ||
577 | amdtp_stream_stop(master); | ||
578 | break_both_connections(bebob); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | mutex_unlock(&bebob->mutex); | ||
583 | } | ||
584 | |||
585 | void snd_bebob_stream_update_duplex(struct snd_bebob *bebob) | ||
586 | { | ||
587 | /* vs. XRUN recovery due to discontinuity at bus reset */ | ||
588 | mutex_lock(&bebob->mutex); | ||
589 | |||
590 | if ((cmp_connection_update(&bebob->in_conn) < 0) || | ||
591 | (cmp_connection_update(&bebob->out_conn) < 0)) { | ||
592 | amdtp_stream_pcm_abort(&bebob->rx_stream); | ||
593 | amdtp_stream_pcm_abort(&bebob->tx_stream); | ||
594 | amdtp_stream_stop(&bebob->rx_stream); | ||
595 | amdtp_stream_stop(&bebob->tx_stream); | ||
596 | break_both_connections(bebob); | ||
597 | } else { | ||
598 | amdtp_stream_update(&bebob->rx_stream); | ||
599 | amdtp_stream_update(&bebob->tx_stream); | ||
600 | } | ||
601 | |||
602 | mutex_unlock(&bebob->mutex); | ||
603 | } | ||
604 | |||
605 | void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) | ||
606 | { | ||
607 | mutex_lock(&bebob->mutex); | ||
608 | |||
609 | amdtp_stream_pcm_abort(&bebob->rx_stream); | ||
610 | amdtp_stream_pcm_abort(&bebob->tx_stream); | ||
611 | |||
612 | amdtp_stream_stop(&bebob->rx_stream); | ||
613 | amdtp_stream_stop(&bebob->tx_stream); | ||
614 | |||
615 | amdtp_stream_destroy(&bebob->rx_stream); | ||
616 | amdtp_stream_destroy(&bebob->tx_stream); | ||
617 | |||
618 | destroy_both_connections(bebob); | ||
619 | |||
620 | mutex_unlock(&bebob->mutex); | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * See: Table 50: Extended Stream Format Info Format Hierarchy Level 2’ | ||
625 | * in Additional AVC commands (Nov 2003, BridgeCo) | ||
626 | * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005 | ||
627 | */ | ||
628 | static int | ||
629 | parse_stream_formation(u8 *buf, unsigned int len, | ||
630 | struct snd_bebob_stream_formation *formation) | ||
631 | { | ||
632 | unsigned int i, e, channels, format; | ||
633 | |||
634 | /* | ||
635 | * this module can support a hierarchy combination that: | ||
636 | * Root: Audio and Music (0x90) | ||
637 | * Level 1: AM824 Compound (0x40) | ||
638 | */ | ||
639 | if ((buf[0] != 0x90) || (buf[1] != 0x40)) | ||
640 | return -ENOSYS; | ||
641 | |||
642 | /* check sampling rate */ | ||
643 | for (i = 0; i < ARRAY_SIZE(bridgeco_freq_table); i++) { | ||
644 | if (buf[2] == bridgeco_freq_table[i]) | ||
645 | break; | ||
646 | } | ||
647 | if (i == sizeof(bridgeco_freq_table)) | ||
648 | return -ENOSYS; | ||
649 | |||
650 | /* Avoid double count by different entries for the same rate. */ | ||
651 | memset(&formation[i], 0, sizeof(struct snd_bebob_stream_formation)); | ||
652 | |||
653 | for (e = 0; e < buf[4]; e++) { | ||
654 | channels = buf[5 + e * 2]; | ||
655 | format = buf[6 + e * 2]; | ||
656 | |||
657 | switch (format) { | ||
658 | /* IEC 60958-3, currently handle as MBLA */ | ||
659 | case 0x00: | ||
660 | /* Multi bit linear audio */ | ||
661 | case 0x06: /* Raw */ | ||
662 | formation[i].pcm += channels; | ||
663 | break; | ||
664 | /* MIDI Conformant */ | ||
665 | case 0x0d: | ||
666 | formation[i].midi += channels; | ||
667 | break; | ||
668 | /* IEC 61937-3 to 7 */ | ||
669 | case 0x01: | ||
670 | case 0x02: | ||
671 | case 0x03: | ||
672 | case 0x04: | ||
673 | case 0x05: | ||
674 | /* Multi bit linear audio */ | ||
675 | case 0x07: /* DVD-Audio */ | ||
676 | case 0x0c: /* High Precision */ | ||
677 | /* One Bit Audio */ | ||
678 | case 0x08: /* (Plain) Raw */ | ||
679 | case 0x09: /* (Plain) SACD */ | ||
680 | case 0x0a: /* (Encoded) Raw */ | ||
681 | case 0x0b: /* (Encoded) SACD */ | ||
682 | /* Synchronization Stream (Stereo Raw audio) */ | ||
683 | case 0x40: | ||
684 | /* Don't care */ | ||
685 | case 0xff: | ||
686 | default: | ||
687 | return -ENOSYS; /* not supported */ | ||
688 | } | ||
689 | } | ||
690 | |||
691 | if (formation[i].pcm > AMDTP_MAX_CHANNELS_FOR_PCM || | ||
692 | formation[i].midi > AMDTP_MAX_CHANNELS_FOR_MIDI) | ||
693 | return -ENOSYS; | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int | ||
699 | fill_stream_formations(struct snd_bebob *bebob, enum avc_bridgeco_plug_dir dir, | ||
700 | unsigned short pid) | ||
701 | { | ||
702 | u8 *buf; | ||
703 | struct snd_bebob_stream_formation *formations; | ||
704 | unsigned int len, eid; | ||
705 | u8 addr[AVC_BRIDGECO_ADDR_BYTES]; | ||
706 | int err; | ||
707 | |||
708 | buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL); | ||
709 | if (buf == NULL) | ||
710 | return -ENOMEM; | ||
711 | |||
712 | if (dir == AVC_BRIDGECO_PLUG_DIR_IN) | ||
713 | formations = bebob->rx_stream_formations; | ||
714 | else | ||
715 | formations = bebob->tx_stream_formations; | ||
716 | |||
717 | for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; eid++) { | ||
718 | len = FORMAT_MAXIMUM_LENGTH; | ||
719 | avc_bridgeco_fill_unit_addr(addr, dir, | ||
720 | AVC_BRIDGECO_PLUG_UNIT_ISOC, pid); | ||
721 | err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf, | ||
722 | &len, eid); | ||
723 | /* No entries remained. */ | ||
724 | if (err == -EINVAL && eid > 0) { | ||
725 | err = 0; | ||
726 | break; | ||
727 | } else if (err < 0) { | ||
728 | dev_err(&bebob->unit->device, | ||
729 | "fail to get stream format %d for isoc %s plug %d:%d\n", | ||
730 | eid, | ||
731 | (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : | ||
732 | "out", | ||
733 | pid, err); | ||
734 | break; | ||
735 | } | ||
736 | |||
737 | err = parse_stream_formation(buf, len, formations); | ||
738 | if (err < 0) | ||
739 | break; | ||
740 | } | ||
741 | |||
742 | kfree(buf); | ||
743 | return err; | ||
744 | } | ||
745 | |||
746 | static int | ||
747 | seek_msu_sync_input_plug(struct snd_bebob *bebob) | ||
748 | { | ||
749 | u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES]; | ||
750 | unsigned int i, type; | ||
751 | int err; | ||
752 | |||
753 | /* Get the number of Music Sub Unit for both direction. */ | ||
754 | err = avc_general_get_plug_info(bebob->unit, 0x0c, 0x00, 0x00, plugs); | ||
755 | if (err < 0) { | ||
756 | dev_err(&bebob->unit->device, | ||
757 | "fail to get info for MSU in/out plugs: %d\n", | ||
758 | err); | ||
759 | goto end; | ||
760 | } | ||
761 | |||
762 | /* seek destination plugs for 'MSU sync input' */ | ||
763 | bebob->sync_input_plug = -1; | ||
764 | for (i = 0; i < plugs[0]; i++) { | ||
765 | avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, i); | ||
766 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | ||
767 | if (err < 0) { | ||
768 | dev_err(&bebob->unit->device, | ||
769 | "fail to get type for MSU in plug %d: %d\n", | ||
770 | i, err); | ||
771 | goto end; | ||
772 | } | ||
773 | |||
774 | if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) { | ||
775 | bebob->sync_input_plug = i; | ||
776 | break; | ||
777 | } | ||
778 | } | ||
779 | end: | ||
780 | return err; | ||
781 | } | ||
782 | |||
783 | int snd_bebob_stream_discover(struct snd_bebob *bebob) | ||
784 | { | ||
785 | u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES]; | ||
786 | enum avc_bridgeco_plug_type type; | ||
787 | unsigned int i; | ||
788 | int err; | ||
789 | |||
790 | /* the number of plugs for isoc in/out, ext in/out */ | ||
791 | err = avc_general_get_plug_info(bebob->unit, 0x1f, 0x07, 0x00, plugs); | ||
792 | if (err < 0) { | ||
793 | dev_err(&bebob->unit->device, | ||
794 | "fail to get info for isoc/external in/out plugs: %d\n", | ||
795 | err); | ||
796 | goto end; | ||
797 | } | ||
798 | |||
799 | /* | ||
800 | * This module supports at least one isoc input plug and one isoc | ||
801 | * output plug. | ||
802 | */ | ||
803 | if ((plugs[0] == 0) || (plugs[1] == 0)) { | ||
804 | err = -ENOSYS; | ||
805 | goto end; | ||
806 | } | ||
807 | |||
808 | avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, | ||
809 | AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); | ||
810 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | ||
811 | if (err < 0) { | ||
812 | dev_err(&bebob->unit->device, | ||
813 | "fail to get type for isoc in plug 0: %d\n", err); | ||
814 | goto end; | ||
815 | } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { | ||
816 | err = -ENOSYS; | ||
817 | goto end; | ||
818 | } | ||
819 | err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_IN, 0); | ||
820 | if (err < 0) | ||
821 | goto end; | ||
822 | |||
823 | avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, | ||
824 | AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); | ||
825 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | ||
826 | if (err < 0) { | ||
827 | dev_err(&bebob->unit->device, | ||
828 | "fail to get type for isoc out plug 0: %d\n", err); | ||
829 | goto end; | ||
830 | } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { | ||
831 | err = -ENOSYS; | ||
832 | goto end; | ||
833 | } | ||
834 | err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_OUT, 0); | ||
835 | if (err < 0) | ||
836 | goto end; | ||
837 | |||
838 | /* count external input plugs for MIDI */ | ||
839 | bebob->midi_input_ports = 0; | ||
840 | for (i = 0; i < plugs[2]; i++) { | ||
841 | avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, | ||
842 | AVC_BRIDGECO_PLUG_UNIT_EXT, i); | ||
843 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | ||
844 | if (err < 0) { | ||
845 | dev_err(&bebob->unit->device, | ||
846 | "fail to get type for external in plug %d: %d\n", | ||
847 | i, err); | ||
848 | goto end; | ||
849 | } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { | ||
850 | bebob->midi_input_ports++; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | /* count external output plugs for MIDI */ | ||
855 | bebob->midi_output_ports = 0; | ||
856 | for (i = 0; i < plugs[3]; i++) { | ||
857 | avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, | ||
858 | AVC_BRIDGECO_PLUG_UNIT_EXT, i); | ||
859 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | ||
860 | if (err < 0) { | ||
861 | dev_err(&bebob->unit->device, | ||
862 | "fail to get type for external out plug %d: %d\n", | ||
863 | i, err); | ||
864 | goto end; | ||
865 | } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { | ||
866 | bebob->midi_output_ports++; | ||
867 | } | ||
868 | } | ||
869 | |||
870 | /* for check source of clock later */ | ||
871 | err = seek_msu_sync_input_plug(bebob); | ||
872 | end: | ||
873 | return err; | ||
874 | } | ||