aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/fcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/fcp.c')
-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 }