diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 09:44:56 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 08:22:37 -0400 |
commit | 44aff6980af107cccda4d6677995c88b9dad3482 (patch) | |
tree | 6ffea09a63a7e1457df1373b66a72b2f65170f63 | |
parent | c68a1c6584d066d0f2b7aa2117d2eddce2d01def (diff) |
ALSA: firewire-lib: Add handling output connection by CMP
This patch adds some macros, codes with condition of direction and new functions
to handle output connection. Once cmp_connection_init() is executed with its
direction, CMP input and output connection can be handled by the same way.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/firewire/cmp.c | 99 |
1 files changed, 90 insertions, 9 deletions
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index c7f7a3164390..9da40d9e79da 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c | |||
@@ -29,6 +29,14 @@ | |||
29 | #define PCR_CHANNEL_MASK 0x003f0000 | 29 | #define PCR_CHANNEL_MASK 0x003f0000 |
30 | #define PCR_CHANNEL_SHIFT 16 | 30 | #define PCR_CHANNEL_SHIFT 16 |
31 | 31 | ||
32 | /* oPCR specific fields */ | ||
33 | #define OPCR_XSPEED_MASK 0x00C00000 | ||
34 | #define OPCR_XSPEED_SHIFT 22 | ||
35 | #define OPCR_SPEED_MASK 0x0000C000 | ||
36 | #define OPCR_SPEED_SHIFT 14 | ||
37 | #define OPCR_OVERHEAD_ID_MASK 0x00003C00 | ||
38 | #define OPCR_OVERHEAD_ID_SHIFT 10 | ||
39 | |||
32 | enum bus_reset_handling { | 40 | enum bus_reset_handling { |
33 | ABORT_ON_BUS_RESET, | 41 | ABORT_ON_BUS_RESET, |
34 | SUCCEED_ON_BUS_RESET, | 42 | SUCCEED_ON_BUS_RESET, |
@@ -41,10 +49,27 @@ void cmp_error(struct cmp_connection *c, const char *fmt, ...) | |||
41 | 49 | ||
42 | va_start(va, fmt); | 50 | va_start(va, fmt); |
43 | dev_err(&c->resources.unit->device, "%cPCR%u: %pV", | 51 | dev_err(&c->resources.unit->device, "%cPCR%u: %pV", |
44 | 'i', c->pcr_index, &(struct va_format){ fmt, &va }); | 52 | (c->direction == CMP_INPUT) ? 'i' : 'o', |
53 | c->pcr_index, &(struct va_format){ fmt, &va }); | ||
45 | va_end(va); | 54 | va_end(va); |
46 | } | 55 | } |
47 | 56 | ||
57 | static u64 mpr_address(struct cmp_connection *c) | ||
58 | { | ||
59 | if (c->direction == CMP_INPUT) | ||
60 | return CSR_REGISTER_BASE + CSR_IMPR; | ||
61 | else | ||
62 | return CSR_REGISTER_BASE + CSR_OMPR; | ||
63 | } | ||
64 | |||
65 | static u64 pcr_address(struct cmp_connection *c) | ||
66 | { | ||
67 | if (c->direction == CMP_INPUT) | ||
68 | return CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index); | ||
69 | else | ||
70 | return CSR_REGISTER_BASE + CSR_OPCR(c->pcr_index); | ||
71 | } | ||
72 | |||
48 | static int pcr_modify(struct cmp_connection *c, | 73 | static int pcr_modify(struct cmp_connection *c, |
49 | __be32 (*modify)(struct cmp_connection *c, __be32 old), | 74 | __be32 (*modify)(struct cmp_connection *c, __be32 old), |
50 | int (*check)(struct cmp_connection *c, __be32 pcr), | 75 | int (*check)(struct cmp_connection *c, __be32 pcr), |
@@ -60,8 +85,7 @@ static int pcr_modify(struct cmp_connection *c, | |||
60 | 85 | ||
61 | err = snd_fw_transaction( | 86 | err = snd_fw_transaction( |
62 | c->resources.unit, TCODE_LOCK_COMPARE_SWAP, | 87 | c->resources.unit, TCODE_LOCK_COMPARE_SWAP, |
63 | CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index), | 88 | pcr_address(c), buffer, 8, |
64 | buffer, 8, | ||
65 | FW_FIXED_GENERATION | c->resources.generation); | 89 | FW_FIXED_GENERATION | c->resources.generation); |
66 | 90 | ||
67 | if (err < 0) { | 91 | if (err < 0) { |
@@ -101,9 +125,9 @@ int cmp_connection_init(struct cmp_connection *c, | |||
101 | u32 mpr; | 125 | u32 mpr; |
102 | int err; | 126 | int err; |
103 | 127 | ||
128 | c->direction = direction; | ||
104 | err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, | 129 | err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, |
105 | CSR_REGISTER_BASE + CSR_IMPR, | 130 | mpr_address(c), &mpr_be, 4, 0); |
106 | &mpr_be, 4, 0); | ||
107 | if (err < 0) | 131 | if (err < 0) |
108 | return err; | 132 | return err; |
109 | mpr = be32_to_cpu(mpr_be); | 133 | mpr = be32_to_cpu(mpr_be); |
@@ -151,6 +175,53 @@ static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr) | |||
151 | return ipcr; | 175 | return ipcr; |
152 | } | 176 | } |
153 | 177 | ||
178 | static int get_overhead_id(struct cmp_connection *c) | ||
179 | { | ||
180 | int id; | ||
181 | |||
182 | /* | ||
183 | * apply "oPCR overhead ID encoding" | ||
184 | * the encoding table can convert up to 512. | ||
185 | * here the value over 512 is converted as the same way as 512. | ||
186 | */ | ||
187 | for (id = 1; id < 16; id++) { | ||
188 | if (c->resources.bandwidth_overhead < (id << 5)) | ||
189 | break; | ||
190 | } | ||
191 | if (id == 16) | ||
192 | id = 0; | ||
193 | |||
194 | return id; | ||
195 | } | ||
196 | |||
197 | static __be32 opcr_set_modify(struct cmp_connection *c, __be32 opcr) | ||
198 | { | ||
199 | unsigned int spd, xspd; | ||
200 | |||
201 | /* generate speed and extended speed field value */ | ||
202 | if (c->speed > SCODE_400) { | ||
203 | spd = SCODE_800; | ||
204 | xspd = c->speed - SCODE_800; | ||
205 | } else { | ||
206 | spd = c->speed; | ||
207 | xspd = 0; | ||
208 | } | ||
209 | |||
210 | opcr &= ~cpu_to_be32(PCR_BCAST_CONN | | ||
211 | PCR_P2P_CONN_MASK | | ||
212 | OPCR_XSPEED_MASK | | ||
213 | PCR_CHANNEL_MASK | | ||
214 | OPCR_SPEED_MASK | | ||
215 | OPCR_OVERHEAD_ID_MASK); | ||
216 | opcr |= cpu_to_be32(1 << PCR_P2P_CONN_SHIFT); | ||
217 | opcr |= cpu_to_be32(xspd << OPCR_XSPEED_SHIFT); | ||
218 | opcr |= cpu_to_be32(c->resources.channel << PCR_CHANNEL_SHIFT); | ||
219 | opcr |= cpu_to_be32(spd << OPCR_SPEED_SHIFT); | ||
220 | opcr |= cpu_to_be32(get_overhead_id(c) << OPCR_OVERHEAD_ID_SHIFT); | ||
221 | |||
222 | return opcr; | ||
223 | } | ||
224 | |||
154 | static int pcr_set_check(struct cmp_connection *c, __be32 pcr) | 225 | static int pcr_set_check(struct cmp_connection *c, __be32 pcr) |
155 | { | 226 | { |
156 | if (pcr & cpu_to_be32(PCR_BCAST_CONN | | 227 | if (pcr & cpu_to_be32(PCR_BCAST_CONN | |
@@ -196,8 +267,13 @@ retry_after_bus_reset: | |||
196 | if (err < 0) | 267 | if (err < 0) |
197 | goto err_mutex; | 268 | goto err_mutex; |
198 | 269 | ||
199 | err = pcr_modify(c, ipcr_set_modify, pcr_set_check, | 270 | if (c->direction == CMP_OUTPUT) |
200 | ABORT_ON_BUS_RESET); | 271 | err = pcr_modify(c, opcr_set_modify, pcr_set_check, |
272 | ABORT_ON_BUS_RESET); | ||
273 | else | ||
274 | err = pcr_modify(c, ipcr_set_modify, pcr_set_check, | ||
275 | ABORT_ON_BUS_RESET); | ||
276 | |||
201 | if (err == -EAGAIN) { | 277 | if (err == -EAGAIN) { |
202 | fw_iso_resources_free(&c->resources); | 278 | fw_iso_resources_free(&c->resources); |
203 | goto retry_after_bus_reset; | 279 | goto retry_after_bus_reset; |
@@ -245,8 +321,13 @@ int cmp_connection_update(struct cmp_connection *c) | |||
245 | if (err < 0) | 321 | if (err < 0) |
246 | goto err_unconnect; | 322 | goto err_unconnect; |
247 | 323 | ||
248 | err = pcr_modify(c, ipcr_set_modify, pcr_set_check, | 324 | if (c->direction == CMP_OUTPUT) |
249 | SUCCEED_ON_BUS_RESET); | 325 | err = pcr_modify(c, opcr_set_modify, pcr_set_check, |
326 | SUCCEED_ON_BUS_RESET); | ||
327 | else | ||
328 | err = pcr_modify(c, ipcr_set_modify, pcr_set_check, | ||
329 | SUCCEED_ON_BUS_RESET); | ||
330 | |||
250 | if (err < 0) | 331 | if (err < 0) |
251 | goto err_resources; | 332 | goto err_resources; |
252 | 333 | ||