0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "dice.h"
0010
0011 static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type,
0012 u64 offset)
0013 {
0014 switch (type) {
0015 case SND_DICE_ADDR_TYPE_TX:
0016 offset += dice->tx_offset;
0017 break;
0018 case SND_DICE_ADDR_TYPE_RX:
0019 offset += dice->rx_offset;
0020 break;
0021 case SND_DICE_ADDR_TYPE_SYNC:
0022 offset += dice->sync_offset;
0023 break;
0024 case SND_DICE_ADDR_TYPE_RSRV:
0025 offset += dice->rsrv_offset;
0026 break;
0027 case SND_DICE_ADDR_TYPE_GLOBAL:
0028 default:
0029 offset += dice->global_offset;
0030 break;
0031 }
0032 offset += DICE_PRIVATE_SPACE;
0033 return offset;
0034 }
0035
0036 int snd_dice_transaction_write(struct snd_dice *dice,
0037 enum snd_dice_addr_type type,
0038 unsigned int offset, void *buf, unsigned int len)
0039 {
0040 return snd_fw_transaction(dice->unit,
0041 (len == 4) ? TCODE_WRITE_QUADLET_REQUEST :
0042 TCODE_WRITE_BLOCK_REQUEST,
0043 get_subaddr(dice, type, offset), buf, len, 0);
0044 }
0045
0046 int snd_dice_transaction_read(struct snd_dice *dice,
0047 enum snd_dice_addr_type type, unsigned int offset,
0048 void *buf, unsigned int len)
0049 {
0050 return snd_fw_transaction(dice->unit,
0051 (len == 4) ? TCODE_READ_QUADLET_REQUEST :
0052 TCODE_READ_BLOCK_REQUEST,
0053 get_subaddr(dice, type, offset), buf, len, 0);
0054 }
0055
0056 static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info)
0057 {
0058 return snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
0059 info, 4);
0060 }
0061
0062 int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
0063 unsigned int *source)
0064 {
0065 __be32 info;
0066 int err;
0067
0068 err = get_clock_info(dice, &info);
0069 if (err >= 0)
0070 *source = be32_to_cpu(info) & CLOCK_SOURCE_MASK;
0071
0072 return err;
0073 }
0074
0075 int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate)
0076 {
0077 __be32 info;
0078 unsigned int index;
0079 int err;
0080
0081 err = get_clock_info(dice, &info);
0082 if (err < 0)
0083 goto end;
0084
0085 index = (be32_to_cpu(info) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT;
0086 if (index >= SND_DICE_RATES_COUNT) {
0087 err = -ENOSYS;
0088 goto end;
0089 }
0090
0091 *rate = snd_dice_rates[index];
0092 end:
0093 return err;
0094 }
0095
0096 int snd_dice_transaction_set_enable(struct snd_dice *dice)
0097 {
0098 __be32 value;
0099 int err = 0;
0100
0101 if (dice->global_enabled)
0102 goto end;
0103
0104 value = cpu_to_be32(1);
0105 err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
0106 get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
0107 GLOBAL_ENABLE),
0108 &value, 4,
0109 FW_FIXED_GENERATION | dice->owner_generation);
0110 if (err < 0)
0111 goto end;
0112
0113 dice->global_enabled = true;
0114 end:
0115 return err;
0116 }
0117
0118 void snd_dice_transaction_clear_enable(struct snd_dice *dice)
0119 {
0120 __be32 value;
0121
0122 value = 0;
0123 snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
0124 get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
0125 GLOBAL_ENABLE),
0126 &value, 4, FW_QUIET |
0127 FW_FIXED_GENERATION | dice->owner_generation);
0128
0129 dice->global_enabled = false;
0130 }
0131
0132 static void dice_notification(struct fw_card *card, struct fw_request *request,
0133 int tcode, int destination, int source,
0134 int generation, unsigned long long offset,
0135 void *data, size_t length, void *callback_data)
0136 {
0137 struct snd_dice *dice = callback_data;
0138 u32 bits;
0139 unsigned long flags;
0140
0141 if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
0142 fw_send_response(card, request, RCODE_TYPE_ERROR);
0143 return;
0144 }
0145 if ((offset & 3) != 0) {
0146 fw_send_response(card, request, RCODE_ADDRESS_ERROR);
0147 return;
0148 }
0149
0150 bits = be32_to_cpup(data);
0151
0152 spin_lock_irqsave(&dice->lock, flags);
0153 dice->notification_bits |= bits;
0154 spin_unlock_irqrestore(&dice->lock, flags);
0155
0156 fw_send_response(card, request, RCODE_COMPLETE);
0157
0158 if (bits & NOTIFY_CLOCK_ACCEPTED)
0159 complete(&dice->clock_accepted);
0160 wake_up(&dice->hwdep_wait);
0161 }
0162
0163 static int register_notification_address(struct snd_dice *dice, bool retry)
0164 {
0165 struct fw_device *device = fw_parent_device(dice->unit);
0166 __be64 *buffer;
0167 unsigned int retries;
0168 int err;
0169
0170 retries = (retry) ? 3 : 0;
0171
0172 buffer = kmalloc(2 * 8, GFP_KERNEL);
0173 if (!buffer)
0174 return -ENOMEM;
0175
0176 for (;;) {
0177 buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
0178 buffer[1] = cpu_to_be64(
0179 ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
0180 dice->notification_handler.offset);
0181
0182 dice->owner_generation = device->generation;
0183 smp_rmb();
0184 err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
0185 get_subaddr(dice,
0186 SND_DICE_ADDR_TYPE_GLOBAL,
0187 GLOBAL_OWNER),
0188 buffer, 2 * 8,
0189 FW_FIXED_GENERATION |
0190 dice->owner_generation);
0191 if (err == 0) {
0192
0193 if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER))
0194 break;
0195
0196 if (buffer[0] == buffer[1])
0197 break;
0198
0199 dev_err(&dice->unit->device,
0200 "device is already in use\n");
0201 err = -EBUSY;
0202 }
0203 if (err != -EAGAIN || retries-- > 0)
0204 break;
0205
0206 msleep(20);
0207 }
0208
0209 kfree(buffer);
0210
0211 if (err < 0)
0212 dice->owner_generation = -1;
0213
0214 return err;
0215 }
0216
0217 static void unregister_notification_address(struct snd_dice *dice)
0218 {
0219 struct fw_device *device = fw_parent_device(dice->unit);
0220 __be64 *buffer;
0221
0222 buffer = kmalloc(2 * 8, GFP_KERNEL);
0223 if (buffer == NULL)
0224 return;
0225
0226 buffer[0] = cpu_to_be64(
0227 ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
0228 dice->notification_handler.offset);
0229 buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
0230 snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
0231 get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
0232 GLOBAL_OWNER),
0233 buffer, 2 * 8, FW_QUIET |
0234 FW_FIXED_GENERATION | dice->owner_generation);
0235
0236 kfree(buffer);
0237
0238 dice->owner_generation = -1;
0239 }
0240
0241 void snd_dice_transaction_destroy(struct snd_dice *dice)
0242 {
0243 struct fw_address_handler *handler = &dice->notification_handler;
0244
0245 if (handler->callback_data == NULL)
0246 return;
0247
0248 unregister_notification_address(dice);
0249
0250 fw_core_remove_address_handler(handler);
0251 handler->callback_data = NULL;
0252 }
0253
0254 int snd_dice_transaction_reinit(struct snd_dice *dice)
0255 {
0256 struct fw_address_handler *handler = &dice->notification_handler;
0257
0258 if (handler->callback_data == NULL)
0259 return -EINVAL;
0260
0261 return register_notification_address(dice, false);
0262 }
0263
0264 static int get_subaddrs(struct snd_dice *dice)
0265 {
0266 static const int min_values[10] = {
0267 10, 0x60 / 4,
0268 10, 0x18 / 4,
0269 10, 0x18 / 4,
0270 0, 0,
0271 0, 0,
0272 };
0273 __be32 *pointers;
0274 __be32 version;
0275 u32 data;
0276 unsigned int i;
0277 int err;
0278
0279 pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
0280 GFP_KERNEL);
0281 if (pointers == NULL)
0282 return -ENOMEM;
0283
0284
0285
0286
0287
0288
0289 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
0290 DICE_PRIVATE_SPACE, pointers,
0291 sizeof(__be32) * ARRAY_SIZE(min_values), 0);
0292 if (err < 0)
0293 goto end;
0294
0295 for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
0296 data = be32_to_cpu(pointers[i]);
0297 if (data < min_values[i] || data >= 0x40000) {
0298 err = -ENODEV;
0299 goto end;
0300 }
0301 }
0302
0303 if (be32_to_cpu(pointers[1]) > 0x18) {
0304
0305
0306
0307
0308 err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
0309 DICE_PRIVATE_SPACE +
0310 be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
0311 &version, sizeof(version), 0);
0312 if (err < 0)
0313 goto end;
0314
0315 if ((version & cpu_to_be32(0xff000000)) !=
0316 cpu_to_be32(0x01000000)) {
0317 dev_err(&dice->unit->device,
0318 "unknown DICE version: 0x%08x\n",
0319 be32_to_cpu(version));
0320 err = -ENODEV;
0321 goto end;
0322 }
0323
0324
0325 dice->clock_caps = 1;
0326 }
0327
0328 dice->global_offset = be32_to_cpu(pointers[0]) * 4;
0329 dice->tx_offset = be32_to_cpu(pointers[2]) * 4;
0330 dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
0331
0332
0333 if (pointers[7])
0334 dice->sync_offset = be32_to_cpu(pointers[6]) * 4;
0335 if (pointers[9])
0336 dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4;
0337 end:
0338 kfree(pointers);
0339 return err;
0340 }
0341
0342 int snd_dice_transaction_init(struct snd_dice *dice)
0343 {
0344 struct fw_address_handler *handler = &dice->notification_handler;
0345 int err;
0346
0347 err = get_subaddrs(dice);
0348 if (err < 0)
0349 return err;
0350
0351
0352 handler->length = 4;
0353 handler->address_callback = dice_notification;
0354 handler->callback_data = dice;
0355 err = fw_core_add_address_handler(handler, &fw_high_memory_region);
0356 if (err < 0) {
0357 handler->callback_data = NULL;
0358 return err;
0359 }
0360
0361
0362 err = register_notification_address(dice, true);
0363 if (err < 0) {
0364 fw_core_remove_address_handler(handler);
0365 handler->callback_data = NULL;
0366 }
0367
0368 return err;
0369 }