aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/fireworks
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/fireworks')
-rw-r--r--sound/firewire/fireworks/fireworks.c21
-rw-r--r--sound/firewire/fireworks/fireworks.h22
-rw-r--r--sound/firewire/fireworks/fireworks_command.c8
-rw-r--r--sound/firewire/fireworks/fireworks_hwdep.c131
-rw-r--r--sound/firewire/fireworks/fireworks_proc.c18
-rw-r--r--sound/firewire/fireworks/fireworks_transaction.c176
6 files changed, 328 insertions, 48 deletions
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c
index f8d06f56618f..a354d26afe9e 100644
--- a/sound/firewire/fireworks/fireworks.c
+++ b/sound/firewire/fireworks/fireworks.c
@@ -24,6 +24,8 @@ MODULE_LICENSE("GPL v2");
24static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 24static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
25static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 25static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
26static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 26static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
27unsigned int snd_efw_resp_buf_size = 1024;
28bool snd_efw_resp_buf_debug = false;
27 29
28module_param_array(index, int, NULL, 0444); 30module_param_array(index, int, NULL, 0444);
29MODULE_PARM_DESC(index, "card index"); 31MODULE_PARM_DESC(index, "card index");
@@ -31,6 +33,11 @@ module_param_array(id, charp, NULL, 0444);
31MODULE_PARM_DESC(id, "ID string"); 33MODULE_PARM_DESC(id, "ID string");
32module_param_array(enable, bool, NULL, 0444); 34module_param_array(enable, bool, NULL, 0444);
33MODULE_PARM_DESC(enable, "enable Fireworks sound card"); 35MODULE_PARM_DESC(enable, "enable Fireworks sound card");
36module_param_named(resp_buf_size, snd_efw_resp_buf_size, uint, 0444);
37MODULE_PARM_DESC(resp_buf_size,
38 "response buffer size (max 4096, default 1024)");
39module_param_named(resp_buf_debug, snd_efw_resp_buf_debug, bool, 0444);
40MODULE_PARM_DESC(resp_buf_debug, "store all responses to buffer");
34 41
35static DEFINE_MUTEX(devices_mutex); 42static DEFINE_MUTEX(devices_mutex);
36static DECLARE_BITMAP(devices_used, SNDRV_CARDS); 43static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
@@ -182,6 +189,7 @@ efw_card_free(struct snd_card *card)
182 } 189 }
183 190
184 mutex_destroy(&efw->mutex); 191 mutex_destroy(&efw->mutex);
192 kfree(efw->resp_buf);
185} 193}
186 194
187static int 195static int
@@ -219,6 +227,17 @@ efw_probe(struct fw_unit *unit,
219 spin_lock_init(&efw->lock); 227 spin_lock_init(&efw->lock);
220 init_waitqueue_head(&efw->hwdep_wait); 228 init_waitqueue_head(&efw->hwdep_wait);
221 229
230 /* prepare response buffer */
231 snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
232 SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
233 efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL);
234 if (efw->resp_buf == NULL) {
235 err = -ENOMEM;
236 goto error;
237 }
238 efw->pull_ptr = efw->push_ptr = efw->resp_buf;
239 snd_efw_transaction_add_instance(efw);
240
222 err = get_hardware_info(efw); 241 err = get_hardware_info(efw);
223 if (err < 0) 242 if (err < 0)
224 goto error; 243 goto error;
@@ -256,6 +275,7 @@ end:
256 mutex_unlock(&devices_mutex); 275 mutex_unlock(&devices_mutex);
257 return err; 276 return err;
258error: 277error:
278 snd_efw_transaction_remove_instance(efw);
259 mutex_unlock(&devices_mutex); 279 mutex_unlock(&devices_mutex);
260 snd_card_free(card); 280 snd_card_free(card);
261 return err; 281 return err;
@@ -274,6 +294,7 @@ static void efw_remove(struct fw_unit *unit)
274 struct snd_efw *efw = dev_get_drvdata(&unit->device); 294 struct snd_efw *efw = dev_get_drvdata(&unit->device);
275 295
276 snd_efw_stream_destroy_duplex(efw); 296 snd_efw_stream_destroy_duplex(efw);
297 snd_efw_transaction_remove_instance(efw);
277 298
278 snd_card_disconnect(efw->card); 299 snd_card_disconnect(efw->card);
279 snd_card_free_when_closed(efw->card); 300 snd_card_free_when_closed(efw->card);
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h
index 4aaf2dce5ec8..494195bd3296 100644
--- a/sound/firewire/fireworks/fireworks.h
+++ b/sound/firewire/fireworks/fireworks.h
@@ -49,6 +49,9 @@
49 */ 49 */
50#define SND_EFW_RESPONSE_MAXIMUM_BYTES 0x200U 50#define SND_EFW_RESPONSE_MAXIMUM_BYTES 0x200U
51 51
52extern unsigned int snd_efw_resp_buf_size;
53extern bool snd_efw_resp_buf_debug;
54
52struct snd_efw_phys_grp { 55struct snd_efw_phys_grp {
53 u8 type; /* see enum snd_efw_grp_type */ 56 u8 type; /* see enum snd_efw_grp_type */
54 u8 count; 57 u8 count;
@@ -97,23 +100,24 @@ struct snd_efw {
97 int dev_lock_count; 100 int dev_lock_count;
98 bool dev_lock_changed; 101 bool dev_lock_changed;
99 wait_queue_head_t hwdep_wait; 102 wait_queue_head_t hwdep_wait;
100};
101 103
102struct snd_efw_transaction { 104 /* response queue */
103 __be32 length; 105 u8 *resp_buf;
104 __be32 version; 106 u8 *pull_ptr;
105 __be32 seqnum; 107 u8 *push_ptr;
106 __be32 category; 108 unsigned int resp_queues;
107 __be32 command;
108 __be32 status;
109 __be32 params[0];
110}; 109};
110
111int snd_efw_transaction_cmd(struct fw_unit *unit,
112 const void *cmd, unsigned int size);
111int snd_efw_transaction_run(struct fw_unit *unit, 113int snd_efw_transaction_run(struct fw_unit *unit,
112 const void *cmd, unsigned int cmd_size, 114 const void *cmd, unsigned int cmd_size,
113 void *resp, unsigned int resp_size); 115 void *resp, unsigned int resp_size);
114int snd_efw_transaction_register(void); 116int snd_efw_transaction_register(void);
115void snd_efw_transaction_unregister(void); 117void snd_efw_transaction_unregister(void);
116void snd_efw_transaction_bus_reset(struct fw_unit *unit); 118void snd_efw_transaction_bus_reset(struct fw_unit *unit);
119void snd_efw_transaction_add_instance(struct snd_efw *efw);
120void snd_efw_transaction_remove_instance(struct snd_efw *efw);
117 121
118struct snd_efw_hwinfo { 122struct snd_efw_hwinfo {
119 u32 flags; 123 u32 flags;
diff --git a/sound/firewire/fireworks/fireworks_command.c b/sound/firewire/fireworks/fireworks_command.c
index d5ea7051ad0c..166f80584c2a 100644
--- a/sound/firewire/fireworks/fireworks_command.c
+++ b/sound/firewire/fireworks/fireworks_command.c
@@ -22,7 +22,8 @@
22 * Information commands. But this module don't use them. 22 * Information commands. But this module don't use them.
23 */ 23 */
24 24
25#define EFW_TRANSACTION_SEQNUM_MAX ((u32)~0) 25#define KERNEL_SEQNUM_MIN (SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 2)
26#define KERNEL_SEQNUM_MAX ((u32)~0)
26 27
27/* for clock source and sampling rate */ 28/* for clock source and sampling rate */
28struct efc_clock { 29struct efc_clock {
@@ -120,8 +121,9 @@ efw_transaction(struct snd_efw *efw, unsigned int category,
120 121
121 /* to keep consistency of sequence number */ 122 /* to keep consistency of sequence number */
122 spin_lock(&efw->lock); 123 spin_lock(&efw->lock);
123 if (efw->seqnum + 2 >= EFW_TRANSACTION_SEQNUM_MAX) 124 if ((efw->seqnum < KERNEL_SEQNUM_MIN) ||
124 efw->seqnum = 0; 125 (efw->seqnum >= KERNEL_SEQNUM_MAX - 2))
126 efw->seqnum = KERNEL_SEQNUM_MIN;
125 else 127 else
126 efw->seqnum += 2; 128 efw->seqnum += 2;
127 seqnum = efw->seqnum; 129 seqnum = efw->seqnum;
diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c
index 1cf491dc39a3..6b50a6796d22 100644
--- a/sound/firewire/fireworks/fireworks_hwdep.c
+++ b/sound/firewire/fireworks/fireworks_hwdep.c
@@ -7,26 +7,101 @@
7 */ 7 */
8 8
9/* 9/*
10 * This codes have three functionalities. 10 * This codes have five functionalities.
11 * 11 *
12 * 1.get information about firewire node 12 * 1.get information about firewire node
13 * 2.get notification about starting/stopping stream 13 * 2.get notification about starting/stopping stream
14 * 3.lock/unlock streaming 14 * 3.lock/unlock streaming
15 * 4.transmit command of EFW transaction
16 * 5.receive response of EFW transaction
17 *
15 */ 18 */
16 19
17#include "fireworks.h" 20#include "fireworks.h"
18 21
19static long 22static long
20hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, 23hwdep_read_resp_buf(struct snd_efw *efw, char __user *buf, long remained,
24 loff_t *offset)
25{
26 unsigned int length, till_end, type;
27 struct snd_efw_transaction *t;
28 long count = 0;
29
30 if (remained < sizeof(type) + sizeof(struct snd_efw_transaction))
31 return -ENOSPC;
32
33 /* data type is SNDRV_FIREWIRE_EVENT_EFW_RESPONSE */
34 type = SNDRV_FIREWIRE_EVENT_EFW_RESPONSE;
35 if (copy_to_user(buf, &type, sizeof(type)))
36 return -EFAULT;
37 remained -= sizeof(type);
38 buf += sizeof(type);
39
40 /* write into buffer as many responses as possible */
41 while (efw->resp_queues > 0) {
42 t = (struct snd_efw_transaction *)(efw->pull_ptr);
43 length = be32_to_cpu(t->length) * sizeof(__be32);
44
45 /* confirm enough space for this response */
46 if (remained < length)
47 break;
48
49 /* copy from ring buffer to user buffer */
50 while (length > 0) {
51 till_end = snd_efw_resp_buf_size -
52 (unsigned int)(efw->pull_ptr - efw->resp_buf);
53 till_end = min_t(unsigned int, length, till_end);
54
55 if (copy_to_user(buf, efw->pull_ptr, till_end))
56 return -EFAULT;
57
58 efw->pull_ptr += till_end;
59 if (efw->pull_ptr >= efw->resp_buf +
60 snd_efw_resp_buf_size)
61 efw->pull_ptr = efw->resp_buf;
62
63 length -= till_end;
64 buf += till_end;
65 count += till_end;
66 remained -= till_end;
67 }
68
69 efw->resp_queues--;
70 }
71
72 return count;
73}
74
75static long
76hwdep_read_locked(struct snd_efw *efw, char __user *buf, long count,
77 loff_t *offset)
78{
79 union snd_firewire_event event;
80
81 memset(&event, 0, sizeof(event));
82
83 event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
84 event.lock_status.status = (efw->dev_lock_count > 0);
85 efw->dev_lock_changed = false;
86
87 count = min_t(long, count, sizeof(event.lock_status));
88
89 if (copy_to_user(buf, &event, count))
90 return -EFAULT;
91
92 return count;
93}
94
95static long
96hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
21 loff_t *offset) 97 loff_t *offset)
22{ 98{
23 struct snd_efw *efw = hwdep->private_data; 99 struct snd_efw *efw = hwdep->private_data;
24 DEFINE_WAIT(wait); 100 DEFINE_WAIT(wait);
25 union snd_firewire_event event;
26 101
27 spin_lock_irq(&efw->lock); 102 spin_lock_irq(&efw->lock);
28 103
29 while (!efw->dev_lock_changed) { 104 while ((!efw->dev_lock_changed) && (efw->resp_queues == 0)) {
30 prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE); 105 prepare_to_wait(&efw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
31 spin_unlock_irq(&efw->lock); 106 spin_unlock_irq(&efw->lock);
32 schedule(); 107 schedule();
@@ -36,20 +111,43 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
36 spin_lock_irq(&efw->lock); 111 spin_lock_irq(&efw->lock);
37 } 112 }
38 113
39 memset(&event, 0, sizeof(event)); 114 if (efw->dev_lock_changed)
40 if (efw->dev_lock_changed) { 115 count = hwdep_read_locked(efw, buf, count, offset);
41 event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; 116 else if (efw->resp_queues > 0)
42 event.lock_status.status = (efw->dev_lock_count > 0); 117 count = hwdep_read_resp_buf(efw, buf, count, offset);
43 efw->dev_lock_changed = false;
44
45 count = min_t(long, count, sizeof(event.lock_status));
46 }
47 118
48 spin_unlock_irq(&efw->lock); 119 spin_unlock_irq(&efw->lock);
49 120
50 if (copy_to_user(buf, &event, count)) 121 return count;
51 return -EFAULT; 122}
52 123
124static long
125hwdep_write(struct snd_hwdep *hwdep, const char __user *data, long count,
126 loff_t *offset)
127{
128 struct snd_efw *efw = hwdep->private_data;
129 u32 seqnum;
130 u8 *buf;
131
132 if (count < sizeof(struct snd_efw_transaction) ||
133 SND_EFW_RESPONSE_MAXIMUM_BYTES < count)
134 return -EINVAL;
135
136 buf = memdup_user(data, count);
137 if (IS_ERR(buf))
138 return PTR_ERR(data);
139
140 /* check seqnum is not for kernel-land */
141 seqnum = be32_to_cpu(((struct snd_efw_transaction *)buf)->seqnum);
142 if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX) {
143 count = -EINVAL;
144 goto end;
145 }
146
147 if (snd_efw_transaction_cmd(efw->unit, buf, count) < 0)
148 count = -EIO;
149end:
150 kfree(buf);
53 return count; 151 return count;
54} 152}
55 153
@@ -62,13 +160,13 @@ hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
62 poll_wait(file, &efw->hwdep_wait, wait); 160 poll_wait(file, &efw->hwdep_wait, wait);
63 161
64 spin_lock_irq(&efw->lock); 162 spin_lock_irq(&efw->lock);
65 if (efw->dev_lock_changed) 163 if (efw->dev_lock_changed || (efw->resp_queues > 0))
66 events = POLLIN | POLLRDNORM; 164 events = POLLIN | POLLRDNORM;
67 else 165 else
68 events = 0; 166 events = 0;
69 spin_unlock_irq(&efw->lock); 167 spin_unlock_irq(&efw->lock);
70 168
71 return events; 169 return events | POLLOUT;
72} 170}
73 171
74static int 172static int
@@ -174,6 +272,7 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
174 272
175static const struct snd_hwdep_ops hwdep_ops = { 273static const struct snd_hwdep_ops hwdep_ops = {
176 .read = hwdep_read, 274 .read = hwdep_read,
275 .write = hwdep_write,
177 .release = hwdep_release, 276 .release = hwdep_release,
178 .poll = hwdep_poll, 277 .poll = hwdep_poll,
179 .ioctl = hwdep_ioctl, 278 .ioctl = hwdep_ioctl,
diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c
index 631c91f64db4..f29d4aaf56a1 100644
--- a/sound/firewire/fireworks/fireworks_proc.c
+++ b/sound/firewire/fireworks/fireworks_proc.c
@@ -176,6 +176,23 @@ end:
176} 176}
177 177
178static void 178static void
179proc_read_queues_state(struct snd_info_entry *entry,
180 struct snd_info_buffer *buffer)
181{
182 struct snd_efw *efw = entry->private_data;
183 unsigned int consumed;
184
185 if (efw->pull_ptr > efw->push_ptr)
186 consumed = snd_efw_resp_buf_size -
187 (unsigned int)(efw->pull_ptr - efw->push_ptr);
188 else
189 consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr);
190
191 snd_iprintf(buffer, "%d %d/%d\n",
192 efw->resp_queues, consumed, snd_efw_resp_buf_size);
193}
194
195static void
179add_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name, 196add_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name,
180 void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b)) 197 void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b))
181{ 198{
@@ -211,4 +228,5 @@ void snd_efw_proc_init(struct snd_efw *efw)
211 add_node(efw, root, "clock", proc_read_clock); 228 add_node(efw, root, "clock", proc_read_clock);
212 add_node(efw, root, "firmware", proc_read_hwinfo); 229 add_node(efw, root, "firmware", proc_read_hwinfo);
213 add_node(efw, root, "meters", proc_read_phys_meters); 230 add_node(efw, root, "meters", proc_read_phys_meters);
231 add_node(efw, root, "queues", proc_read_queues_state);
214} 232}
diff --git a/sound/firewire/fireworks/fireworks_transaction.c b/sound/firewire/fireworks/fireworks_transaction.c
index aac91d8485d5..81a65ebb5f71 100644
--- a/sound/firewire/fireworks/fireworks_transaction.c
+++ b/sound/firewire/fireworks/fireworks_transaction.c
@@ -38,6 +38,9 @@
38#define ERROR_DELAY_MS 5 38#define ERROR_DELAY_MS 5
39#define EFC_TIMEOUT_MS 125 39#define EFC_TIMEOUT_MS 125
40 40
41static DEFINE_SPINLOCK(instances_lock);
42static struct snd_efw *instances[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
43
41static DEFINE_SPINLOCK(transaction_queues_lock); 44static DEFINE_SPINLOCK(transaction_queues_lock);
42static LIST_HEAD(transaction_queues); 45static LIST_HEAD(transaction_queues);
43 46
@@ -57,6 +60,14 @@ struct transaction_queue {
57 wait_queue_head_t wait; 60 wait_queue_head_t wait;
58}; 61};
59 62
63int snd_efw_transaction_cmd(struct fw_unit *unit,
64 const void *cmd, unsigned int size)
65{
66 return snd_fw_transaction(unit, TCODE_WRITE_BLOCK_REQUEST,
67 MEMORY_SPACE_EFW_COMMAND,
68 (void *)cmd, size, 0);
69}
70
60int snd_efw_transaction_run(struct fw_unit *unit, 71int snd_efw_transaction_run(struct fw_unit *unit,
61 const void *cmd, unsigned int cmd_size, 72 const void *cmd, unsigned int cmd_size,
62 void *resp, unsigned int resp_size) 73 void *resp, unsigned int resp_size)
@@ -78,9 +89,7 @@ int snd_efw_transaction_run(struct fw_unit *unit,
78 89
79 tries = 0; 90 tries = 0;
80 do { 91 do {
81 ret = snd_fw_transaction(unit, TCODE_WRITE_BLOCK_REQUEST, 92 ret = snd_efw_transaction_cmd(t.unit, (void *)cmd, cmd_size);
82 MEMORY_SPACE_EFW_COMMAND,
83 (void *)cmd, cmd_size, 0);
84 if (ret < 0) 93 if (ret < 0)
85 break; 94 break;
86 95
@@ -107,27 +116,92 @@ int snd_efw_transaction_run(struct fw_unit *unit,
107} 116}
108 117
109static void 118static void
110efw_response(struct fw_card *card, struct fw_request *request, 119copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
111 int tcode, int destination, int source,
112 int generation, unsigned long long offset,
113 void *data, size_t length, void *callback_data)
114{ 120{
115 struct fw_device *device; 121 size_t capacity, till_end;
116 struct transaction_queue *t; 122 struct snd_efw_transaction *t;
117 unsigned long flags;
118 int rcode;
119 u32 seqnum;
120 123
121 rcode = RCODE_TYPE_ERROR; 124 spin_lock_irq(&efw->lock);
122 if (length < sizeof(struct snd_efw_transaction)) { 125
123 rcode = RCODE_DATA_ERROR; 126 t = (struct snd_efw_transaction *)data;
124 goto end; 127 length = min_t(size_t, t->length * sizeof(t->length), length);
125 } else if (offset != MEMORY_SPACE_EFW_RESPONSE) { 128
126 rcode = RCODE_ADDRESS_ERROR; 129 if (efw->push_ptr < efw->pull_ptr)
130 capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
131 else
132 capacity = snd_efw_resp_buf_size -
133 (unsigned int)(efw->push_ptr - efw->pull_ptr);
134
135 /* confirm enough space for this response */
136 if (capacity < length) {
137 *rcode = RCODE_CONFLICT_ERROR;
127 goto end; 138 goto end;
128 } 139 }
129 140
130 seqnum = be32_to_cpu(((struct snd_efw_transaction *)data)->seqnum); 141 /* copy to ring buffer */
142 while (length > 0) {
143 till_end = snd_efw_resp_buf_size -
144 (unsigned int)(efw->push_ptr - efw->resp_buf);
145 till_end = min_t(unsigned int, length, till_end);
146
147 memcpy(efw->push_ptr, data, till_end);
148
149 efw->push_ptr += till_end;
150 if (efw->push_ptr >= efw->resp_buf + snd_efw_resp_buf_size)
151 efw->push_ptr = efw->resp_buf;
152
153 length -= till_end;
154 data += till_end;
155 }
156
157 /* for hwdep */
158 efw->resp_queues++;
159 wake_up(&efw->hwdep_wait);
160
161 *rcode = RCODE_COMPLETE;
162end:
163 spin_unlock_irq(&efw->lock);
164}
165
166static void
167handle_resp_for_user(struct fw_card *card, int generation, int source,
168 void *data, size_t length, int *rcode)
169{
170 struct fw_device *device;
171 struct snd_efw *efw;
172 unsigned int i;
173
174 spin_lock_irq(&instances_lock);
175
176 for (i = 0; i < SNDRV_CARDS; i++) {
177 efw = instances[i];
178 if (efw == NULL)
179 continue;
180 device = fw_parent_device(efw->unit);
181 if ((device->card != card) ||
182 (device->generation != generation))
183 continue;
184 smp_rmb(); /* node id vs. generation */
185 if (device->node_id != source)
186 continue;
187
188 break;
189 }
190 if (i == SNDRV_CARDS)
191 goto end;
192
193 copy_resp_to_buf(efw, data, length, rcode);
194end:
195 spin_unlock_irq(&instances_lock);
196}
197
198static void
199handle_resp_for_kernel(struct fw_card *card, int generation, int source,
200 void *data, size_t length, int *rcode, u32 seqnum)
201{
202 struct fw_device *device;
203 struct transaction_queue *t;
204 unsigned long flags;
131 205
132 spin_lock_irqsave(&transaction_queues_lock, flags); 206 spin_lock_irqsave(&transaction_queues_lock, flags);
133 list_for_each_entry(t, &transaction_queues, list) { 207 list_for_each_entry(t, &transaction_queues, list) {
@@ -144,14 +218,76 @@ efw_response(struct fw_card *card, struct fw_request *request,
144 t->size = min_t(unsigned int, length, t->size); 218 t->size = min_t(unsigned int, length, t->size);
145 memcpy(t->buf, data, t->size); 219 memcpy(t->buf, data, t->size);
146 wake_up(&t->wait); 220 wake_up(&t->wait);
147 rcode = RCODE_COMPLETE; 221 *rcode = RCODE_COMPLETE;
148 } 222 }
149 } 223 }
150 spin_unlock_irqrestore(&transaction_queues_lock, flags); 224 spin_unlock_irqrestore(&transaction_queues_lock, flags);
225}
226
227static void
228efw_response(struct fw_card *card, struct fw_request *request,
229 int tcode, int destination, int source,
230 int generation, unsigned long long offset,
231 void *data, size_t length, void *callback_data)
232{
233 int rcode, dummy;
234 u32 seqnum;
235
236 rcode = RCODE_TYPE_ERROR;
237 if (length < sizeof(struct snd_efw_transaction)) {
238 rcode = RCODE_DATA_ERROR;
239 goto end;
240 } else if (offset != MEMORY_SPACE_EFW_RESPONSE) {
241 rcode = RCODE_ADDRESS_ERROR;
242 goto end;
243 }
244
245 seqnum = be32_to_cpu(((struct snd_efw_transaction *)data)->seqnum);
246 if (seqnum > SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 1) {
247 handle_resp_for_kernel(card, generation, source,
248 data, length, &rcode, seqnum);
249 if (snd_efw_resp_buf_debug)
250 handle_resp_for_user(card, generation, source,
251 data, length, &dummy);
252 } else {
253 handle_resp_for_user(card, generation, source,
254 data, length, &rcode);
255 }
151end: 256end:
152 fw_send_response(card, request, rcode); 257 fw_send_response(card, request, rcode);
153} 258}
154 259
260void snd_efw_transaction_add_instance(struct snd_efw *efw)
261{
262 unsigned int i;
263
264 spin_lock_irq(&instances_lock);
265
266 for (i = 0; i < SNDRV_CARDS; i++) {
267 if (instances[i] != NULL)
268 continue;
269 instances[i] = efw;
270 break;
271 }
272
273 spin_unlock_irq(&instances_lock);
274}
275
276void snd_efw_transaction_remove_instance(struct snd_efw *efw)
277{
278 unsigned int i;
279
280 spin_lock_irq(&instances_lock);
281
282 for (i = 0; i < SNDRV_CARDS; i++) {
283 if (instances[i] != efw)
284 continue;
285 instances[i] = NULL;
286 }
287
288 spin_unlock_irq(&instances_lock);
289}
290
155void snd_efw_transaction_bus_reset(struct fw_unit *unit) 291void snd_efw_transaction_bus_reset(struct fw_unit *unit)
156{ 292{
157 struct transaction_queue *t; 293 struct transaction_queue *t;