To handle CMP output connection, this patch adds some macros, codes with condition of direction and new functions. 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 --- sound/firewire/cmp.c | 106 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 9 deletions(-)
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index a8d3d5f..334744d 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c @@ -29,6 +29,16 @@ #define PCR_CHANNEL_MASK 0x003f0000 #define PCR_CHANNEL_SHIFT 16
+/* oPCR specific fields */ +#define OPCR_XSPEED_MASK 0x00C00000 +#define OPCR_XSPEED_SHIFT 22 +#define OPCR_SPEED_MASK 0x0000C000 +#define OPCR_SPEED_SHIFT 14 +#define OPCR_OVERHEAD_ID_MASK 0x00003C00 +#define OPCR_OVERHEAD_ID_SHIFT 10 +#define OPCR_PAYLOAD_MASK 0x000003FF +#define OPCR_PAYLOAD_SHIFT 0 + enum bus_reset_handling { ABORT_ON_BUS_RESET, SUCCEED_ON_BUS_RESET, @@ -41,7 +51,8 @@ void cmp_error(struct cmp_connection *c, const char *fmt, ...)
va_start(va, fmt); dev_err(&c->resources.unit->device, "%cPCR%u: %pV", - 'i', c->pcr_index, &(struct va_format){ fmt, &va }); + (c->direction == CMP_INPUT) ? 'i' : 'o', + c->pcr_index, &(struct va_format){ fmt, &va }); va_end(va); }
@@ -54,8 +65,14 @@ static int pcr_modify(struct cmp_connection *c, int generation = c->resources.generation; int rcode, errors = 0; __be32 old_arg, buffer[2]; + unsigned long long offset; int err;
+ if (c->direction == CMP_INPUT) + offset = CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index); + else + offset = CSR_REGISTER_BASE + CSR_OPCR(c->pcr_index); + buffer[0] = c->last_pcr_value; for (;;) { old_arg = buffer[0]; @@ -64,8 +81,7 @@ static int pcr_modify(struct cmp_connection *c, rcode = fw_run_transaction( device->card, TCODE_LOCK_COMPARE_SWAP, device->node_id, generation, device->max_speed, - CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index), - buffer, 8); + offset, buffer, 8);
if (rcode == RCODE_COMPLETE) { if (buffer[0] == old_arg) /* success? */ @@ -107,11 +123,16 @@ int cmp_connection_init(struct cmp_connection *c, { __be32 mpr_be; u32 mpr; + unsigned long long offset; int err;
+ if (c->direction == CMP_INPUT) + offset = CSR_REGISTER_BASE + CSR_IMPR; + else + offset = CSR_REGISTER_BASE + CSR_OMPR; + err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - CSR_REGISTER_BASE + CSR_IMPR, - &mpr_be, 4); + offset, &mpr_be, 4); if (err < 0) return err; mpr = be32_to_cpu(mpr_be); @@ -130,6 +151,7 @@ int cmp_connection_init(struct cmp_connection *c, c->max_speed = (mpr & MPR_SPEED_MASK) >> MPR_SPEED_SHIFT; if (c->max_speed == SCODE_BETA) c->max_speed += (mpr & MPR_XSPEED_MASK) >> MPR_XSPEED_SHIFT; + c->direction = direction;
return 0; } @@ -159,6 +181,62 @@ static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr) return ipcr; }
+static int get_overhead_id(struct cmp_connection *c) +{ + int id; + + /* + * apply "oPCR overhead ID encoding" + * the encoding table can convert up to 512. + * here the value over 512 is converted as the same way as 512. + */ + for (id = 1; id < 16; id += 1) { + if (c->resources.bandwidth_overhead < (id << 5)) + break; + } + if (id == 16) + id = 0; + + return id; +} + +static __be32 opcr_set_modify(struct cmp_connection *c, __be32 opcr) +{ + unsigned int spd, xspd; + + /* generate speed and extended speed field value */ + if (c->speed > SCODE_400) { + spd = SCODE_800; + xspd = c->speed - SCODE_800; + } else { + spd = c->speed; + xspd = 0; + } + + opcr &= ~cpu_to_be32(PCR_BCAST_CONN | + PCR_P2P_CONN_MASK | + OPCR_XSPEED_MASK | + PCR_CHANNEL_MASK | + OPCR_SPEED_MASK | + OPCR_OVERHEAD_ID_MASK | + OPCR_PAYLOAD_MASK); + opcr |= cpu_to_be32(1 << PCR_P2P_CONN_SHIFT); + opcr |= cpu_to_be32(xspd << OPCR_XSPEED_SHIFT); + opcr |= cpu_to_be32(c->resources.channel << PCR_CHANNEL_SHIFT); + opcr |= cpu_to_be32(spd << OPCR_SPEED_SHIFT); + opcr |= cpu_to_be32(get_overhead_id(c) << OPCR_OVERHEAD_ID_SHIFT); + /* + * here zero is applied to payload field. + * it means the maximum number of quadlets in an isochronous packet is + * 1024 when spd is less than three, 1024 * 2 * xspd + 1 when spd is + * equal to three. An arbitrary value can be set here but 0 is enough + * for our purpose. + */ + opcr |= cpu_to_be32(0 << OPCR_PAYLOAD_SHIFT); + + return opcr; +} + static int pcr_set_check(struct cmp_connection *c, __be32 pcr) { if (pcr & cpu_to_be32(PCR_BCAST_CONN | @@ -204,8 +282,13 @@ retry_after_bus_reset: if (err < 0) goto err_mutex;
- err = pcr_modify(c, ipcr_set_modify, pcr_set_check, - ABORT_ON_BUS_RESET); + if (c->direction == CMP_OUTPUT) + err = pcr_modify(c, opcr_set_modify, pcr_set_check, + ABORT_ON_BUS_RESET); + else + err = pcr_modify(c, ipcr_set_modify, pcr_set_check, + ABORT_ON_BUS_RESET); + if (err == -EAGAIN) { fw_iso_resources_free(&c->resources); goto retry_after_bus_reset; @@ -253,8 +336,13 @@ int cmp_connection_update(struct cmp_connection *c) if (err < 0) goto err_unconnect;
- err = pcr_modify(c, ipcr_set_modify, pcr_set_check, - SUCCEED_ON_BUS_RESET); + if (c->direction == CMP_OUTPUT) + err = pcr_modify(c, opcr_set_modify, pcr_set_check, + SUCCEED_ON_BUS_RESET); + else + err = pcr_modify(c, ipcr_set_modify, pcr_set_check, + SUCCEED_ON_BUS_RESET); + if (err < 0) goto err_resources;