aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-04-25 09:44:58 -0400
committerTakashi Iwai <tiwai@suse.de>2014-05-26 08:22:56 -0400
commit00a7bb81c20f3e81711e28e0f6c08cee8fd18514 (patch)
tree6ddf41512c74fe7b462264f708fd9bdd9bde4d95
parentb04479fb8540c906f0ad17f21e4c2715f6e8e7a3 (diff)
ALSA: firewire-lib: Add support for deferred transaction
Some devices based on BeBoB use this type of AV/C transaction. 'Deferred Transaction' is defined in 'AV/C Digital Interface Command Set General Specification' and is used by targets to make a response deferred during processing it. If a target may not be able to complete a command within 100msec since receiving the command, then the target shall return INTERIM response, to which final response will follow later. CONTROL/NOTIFY commands are allowed for deferred transaction. In the specification, devices allow to send INTERIM response just one time. But this commit allows to handle several INTERIM response with two reasons. One reason is to simplify codes, and another reason is to prepare for devices which is out of specification. There is an issue. In the specification, the interval between INTERIM response and final response is 'Unspecified interval'. The specification depends on each subunit specification for this interval. But we promise to finish this function for caller. In this reason, I use FCP_TIMEOUT_MS for this interval. Currently it's 125msec. When we find devices which needs more time for this interval, then let us add some codes to apply more interval for 'Unspecified interval'. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/firewire/fcp.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c
index 860c08073c59..6876bfa9f27d 100644
--- a/sound/firewire/fcp.c
+++ b/sound/firewire/fcp.c
@@ -30,6 +30,7 @@ enum fcp_state {
30 STATE_PENDING, 30 STATE_PENDING,
31 STATE_BUS_RESET, 31 STATE_BUS_RESET,
32 STATE_COMPLETE, 32 STATE_COMPLETE,
33 STATE_DEFERRED,
33}; 34};
34 35
35struct fcp_transaction { 36struct fcp_transaction {
@@ -40,6 +41,7 @@ struct fcp_transaction {
40 unsigned int response_match_bytes; 41 unsigned int response_match_bytes;
41 enum fcp_state state; 42 enum fcp_state state;
42 wait_queue_head_t wait; 43 wait_queue_head_t wait;
44 bool deferrable;
43}; 45};
44 46
45/** 47/**
@@ -81,6 +83,9 @@ int fcp_avc_transaction(struct fw_unit *unit,
81 t.state = STATE_PENDING; 83 t.state = STATE_PENDING;
82 init_waitqueue_head(&t.wait); 84 init_waitqueue_head(&t.wait);
83 85
86 if (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03)
87 t.deferrable = true;
88
84 spin_lock_irq(&transactions_lock); 89 spin_lock_irq(&transactions_lock);
85 list_add_tail(&t.list, &transactions); 90 list_add_tail(&t.list, &transactions);
86 spin_unlock_irq(&transactions_lock); 91 spin_unlock_irq(&transactions_lock);
@@ -93,11 +98,21 @@ int fcp_avc_transaction(struct fw_unit *unit,
93 (void *)command, command_size, 0); 98 (void *)command, command_size, 0);
94 if (ret < 0) 99 if (ret < 0)
95 break; 100 break;
96 101deferred:
97 wait_event_timeout(t.wait, t.state != STATE_PENDING, 102 wait_event_timeout(t.wait, t.state != STATE_PENDING,
98 msecs_to_jiffies(FCP_TIMEOUT_MS)); 103 msecs_to_jiffies(FCP_TIMEOUT_MS));
99 104
100 if (t.state == STATE_COMPLETE) { 105 if (t.state == STATE_DEFERRED) {
106 /*
107 * 'AV/C General Specification' define no time limit
108 * on command completion once an INTERIM response has
109 * been sent. but we promise to finish this function
110 * for a caller. Here we use FCP_TIMEOUT_MS for next
111 * interval. This is not in the specification.
112 */
113 t.state = STATE_PENDING;
114 goto deferred;
115 } else if (t.state == STATE_COMPLETE) {
101 ret = t.response_size; 116 ret = t.response_size;
102 break; 117 break;
103 } else if (t.state == STATE_BUS_RESET) { 118 } else if (t.state == STATE_BUS_RESET) {
@@ -132,7 +147,8 @@ void fcp_bus_reset(struct fw_unit *unit)
132 spin_lock_irq(&transactions_lock); 147 spin_lock_irq(&transactions_lock);
133 list_for_each_entry(t, &transactions, list) { 148 list_for_each_entry(t, &transactions, list) {
134 if (t->unit == unit && 149 if (t->unit == unit &&
135 t->state == STATE_PENDING) { 150 (t->state == STATE_PENDING ||
151 t->state == STATE_DEFERRED)) {
136 t->state = STATE_BUS_RESET; 152 t->state = STATE_BUS_RESET;
137 wake_up(&t->wait); 153 wake_up(&t->wait);
138 } 154 }
@@ -186,10 +202,15 @@ static void fcp_response(struct fw_card *card, struct fw_request *request,
186 202
187 if (t->state == STATE_PENDING && 203 if (t->state == STATE_PENDING &&
188 is_matching_response(t, data, length)) { 204 is_matching_response(t, data, length)) {
189 t->state = STATE_COMPLETE; 205 if (t->deferrable && *(const u8 *)data == 0x0f) {
190 t->response_size = min((unsigned int)length, 206 t->state = STATE_DEFERRED;
191 t->response_size); 207 } else {
192 memcpy(t->response_buffer, data, t->response_size); 208 t->state = STATE_COMPLETE;
209 t->response_size = min_t(unsigned int, length,
210 t->response_size);
211 memcpy(t->response_buffer, data,
212 t->response_size);
213 }
193 wake_up(&t->wait); 214 wake_up(&t->wait);
194 } 215 }
195 } 216 }