2 * dice_transaction.c - a part of driver for Dice based devices
4 * Copyright (c) Clemens Ladisch
5 * Copyright (c) 2014 Takashi Sakamoto
7 * Licensed under the terms of the GNU General Public License, version 2.
12 #define NOTIFICATION_TIMEOUT_MS 100
14 static u64
get_subaddr(struct snd_dice
*dice
, enum snd_dice_addr_type type
,
18 case SND_DICE_ADDR_TYPE_TX
:
19 offset
+= dice
->tx_offset
;
21 case SND_DICE_ADDR_TYPE_RX
:
22 offset
+= dice
->rx_offset
;
24 case SND_DICE_ADDR_TYPE_SYNC
:
25 offset
+= dice
->sync_offset
;
27 case SND_DICE_ADDR_TYPE_RSRV
:
28 offset
+= dice
->rsrv_offset
;
30 case SND_DICE_ADDR_TYPE_GLOBAL
:
32 offset
+= dice
->global_offset
;
35 offset
+= DICE_PRIVATE_SPACE
;
39 int snd_dice_transaction_write(struct snd_dice
*dice
,
40 enum snd_dice_addr_type type
,
41 unsigned int offset
, void *buf
, unsigned int len
)
43 return snd_fw_transaction(dice
->unit
,
44 (len
== 4) ? TCODE_WRITE_QUADLET_REQUEST
:
45 TCODE_WRITE_BLOCK_REQUEST
,
46 get_subaddr(dice
, type
, offset
), buf
, len
, 0);
49 int snd_dice_transaction_read(struct snd_dice
*dice
,
50 enum snd_dice_addr_type type
, unsigned int offset
,
51 void *buf
, unsigned int len
)
53 return snd_fw_transaction(dice
->unit
,
54 (len
== 4) ? TCODE_READ_QUADLET_REQUEST
:
55 TCODE_READ_BLOCK_REQUEST
,
56 get_subaddr(dice
, type
, offset
), buf
, len
, 0);
59 static unsigned int get_clock_info(struct snd_dice
*dice
, __be32
*info
)
61 return snd_dice_transaction_read_global(dice
, GLOBAL_CLOCK_SELECT
,
65 static int set_clock_info(struct snd_dice
*dice
,
66 unsigned int rate
, unsigned int source
)
68 unsigned int retries
= 3;
75 err
= get_clock_info(dice
, &info
);
79 clock
= be32_to_cpu(info
);
80 if (source
!= UINT_MAX
) {
81 mask
= CLOCK_SOURCE_MASK
;
85 if (rate
!= UINT_MAX
) {
86 for (i
= 0; i
< ARRAY_SIZE(snd_dice_rates
); i
++) {
87 if (snd_dice_rates
[i
] == rate
)
90 if (i
== ARRAY_SIZE(snd_dice_rates
)) {
95 mask
= CLOCK_RATE_MASK
;
97 clock
|= i
<< CLOCK_RATE_SHIFT
;
99 info
= cpu_to_be32(clock
);
101 if (completion_done(&dice
->clock_accepted
))
102 reinit_completion(&dice
->clock_accepted
);
104 err
= snd_dice_transaction_write_global(dice
, GLOBAL_CLOCK_SELECT
,
109 /* Timeout means it's invalid request, probably bus reset occurred. */
110 if (wait_for_completion_timeout(&dice
->clock_accepted
,
111 msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS
)) == 0) {
112 if (retries
-- == 0) {
117 err
= snd_dice_transaction_reinit(dice
);
121 msleep(500); /* arbitrary */
128 int snd_dice_transaction_get_clock_source(struct snd_dice
*dice
,
129 unsigned int *source
)
134 err
= get_clock_info(dice
, &info
);
136 *source
= be32_to_cpu(info
) & CLOCK_SOURCE_MASK
;
141 int snd_dice_transaction_get_rate(struct snd_dice
*dice
, unsigned int *rate
)
147 err
= get_clock_info(dice
, &info
);
151 index
= (be32_to_cpu(info
) & CLOCK_RATE_MASK
) >> CLOCK_RATE_SHIFT
;
152 if (index
>= SND_DICE_RATES_COUNT
) {
157 *rate
= snd_dice_rates
[index
];
161 int snd_dice_transaction_set_rate(struct snd_dice
*dice
, unsigned int rate
)
163 return set_clock_info(dice
, rate
, UINT_MAX
);
166 int snd_dice_transaction_set_enable(struct snd_dice
*dice
)
171 if (dice
->global_enabled
)
174 value
= cpu_to_be32(1);
175 err
= snd_fw_transaction(dice
->unit
, TCODE_WRITE_QUADLET_REQUEST
,
176 get_subaddr(dice
, SND_DICE_ADDR_TYPE_GLOBAL
,
179 FW_FIXED_GENERATION
| dice
->owner_generation
);
183 dice
->global_enabled
= true;
188 void snd_dice_transaction_clear_enable(struct snd_dice
*dice
)
193 snd_fw_transaction(dice
->unit
, TCODE_WRITE_QUADLET_REQUEST
,
194 get_subaddr(dice
, SND_DICE_ADDR_TYPE_GLOBAL
,
196 &value
, 4, FW_QUIET
|
197 FW_FIXED_GENERATION
| dice
->owner_generation
);
199 dice
->global_enabled
= false;
202 static void dice_notification(struct fw_card
*card
, struct fw_request
*request
,
203 int tcode
, int destination
, int source
,
204 int generation
, unsigned long long offset
,
205 void *data
, size_t length
, void *callback_data
)
207 struct snd_dice
*dice
= callback_data
;
211 if (tcode
!= TCODE_WRITE_QUADLET_REQUEST
) {
212 fw_send_response(card
, request
, RCODE_TYPE_ERROR
);
215 if ((offset
& 3) != 0) {
216 fw_send_response(card
, request
, RCODE_ADDRESS_ERROR
);
220 bits
= be32_to_cpup(data
);
222 spin_lock_irqsave(&dice
->lock
, flags
);
223 dice
->notification_bits
|= bits
;
224 spin_unlock_irqrestore(&dice
->lock
, flags
);
226 fw_send_response(card
, request
, RCODE_COMPLETE
);
228 if (bits
& NOTIFY_CLOCK_ACCEPTED
)
229 complete(&dice
->clock_accepted
);
230 wake_up(&dice
->hwdep_wait
);
233 static int register_notification_address(struct snd_dice
*dice
, bool retry
)
235 struct fw_device
*device
= fw_parent_device(dice
->unit
);
237 unsigned int retries
;
240 retries
= (retry
) ? 3 : 0;
242 buffer
= kmalloc(2 * 8, GFP_KERNEL
);
247 buffer
[0] = cpu_to_be64(OWNER_NO_OWNER
);
248 buffer
[1] = cpu_to_be64(
249 ((u64
)device
->card
->node_id
<< OWNER_NODE_SHIFT
) |
250 dice
->notification_handler
.offset
);
252 dice
->owner_generation
= device
->generation
;
253 smp_rmb(); /* node_id vs. generation */
254 err
= snd_fw_transaction(dice
->unit
, TCODE_LOCK_COMPARE_SWAP
,
256 SND_DICE_ADDR_TYPE_GLOBAL
,
259 FW_FIXED_GENERATION
|
260 dice
->owner_generation
);
263 if (buffer
[0] == cpu_to_be64(OWNER_NO_OWNER
))
265 /* The address seems to be already registered. */
266 if (buffer
[0] == buffer
[1])
269 dev_err(&dice
->unit
->device
,
270 "device is already in use\n");
273 if (err
!= -EAGAIN
|| retries
-- > 0)
282 dice
->owner_generation
= -1;
287 static void unregister_notification_address(struct snd_dice
*dice
)
289 struct fw_device
*device
= fw_parent_device(dice
->unit
);
292 buffer
= kmalloc(2 * 8, GFP_KERNEL
);
296 buffer
[0] = cpu_to_be64(
297 ((u64
)device
->card
->node_id
<< OWNER_NODE_SHIFT
) |
298 dice
->notification_handler
.offset
);
299 buffer
[1] = cpu_to_be64(OWNER_NO_OWNER
);
300 snd_fw_transaction(dice
->unit
, TCODE_LOCK_COMPARE_SWAP
,
301 get_subaddr(dice
, SND_DICE_ADDR_TYPE_GLOBAL
,
303 buffer
, 2 * 8, FW_QUIET
|
304 FW_FIXED_GENERATION
| dice
->owner_generation
);
308 dice
->owner_generation
= -1;
311 void snd_dice_transaction_destroy(struct snd_dice
*dice
)
313 struct fw_address_handler
*handler
= &dice
->notification_handler
;
315 if (handler
->callback_data
== NULL
)
318 unregister_notification_address(dice
);
320 fw_core_remove_address_handler(handler
);
321 handler
->callback_data
= NULL
;
324 int snd_dice_transaction_reinit(struct snd_dice
*dice
)
326 struct fw_address_handler
*handler
= &dice
->notification_handler
;
328 if (handler
->callback_data
== NULL
)
331 return register_notification_address(dice
, false);
334 int snd_dice_transaction_init(struct snd_dice
*dice
)
336 struct fw_address_handler
*handler
= &dice
->notification_handler
;
340 /* Use the same way which dice_interface_check() does. */
341 pointers
= kmalloc(sizeof(__be32
) * 10, GFP_KERNEL
);
342 if (pointers
== NULL
)
345 /* Get offsets for sub-addresses */
346 err
= snd_fw_transaction(dice
->unit
, TCODE_READ_BLOCK_REQUEST
,
348 pointers
, sizeof(__be32
) * 10, 0);
352 /* Allocation callback in address space over host controller */
354 handler
->address_callback
= dice_notification
;
355 handler
->callback_data
= dice
;
356 err
= fw_core_add_address_handler(handler
, &fw_high_memory_region
);
358 handler
->callback_data
= NULL
;
362 /* Register the address space */
363 err
= register_notification_address(dice
, true);
365 fw_core_remove_address_handler(handler
);
366 handler
->callback_data
= NULL
;
370 dice
->global_offset
= be32_to_cpu(pointers
[0]) * 4;
371 dice
->tx_offset
= be32_to_cpu(pointers
[2]) * 4;
372 dice
->rx_offset
= be32_to_cpu(pointers
[4]) * 4;
373 dice
->sync_offset
= be32_to_cpu(pointers
[6]) * 4;
374 dice
->rsrv_offset
= be32_to_cpu(pointers
[8]) * 4;
377 if (be32_to_cpu(pointers
[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES
+ 4)
378 dice
->clock_caps
= 1;