^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Apple iSight audio driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/byteorder.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/firewire.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/firewire-constants.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mod_devicetable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <sound/control.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <sound/initval.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <sound/tlv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "lib.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "iso-resources.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include "packets-buffer.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define OUI_APPLE 0x000a27
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define MODEL_APPLE_ISIGHT 0x000008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define SW_ISIGHT_AUDIO 0x000010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define REG_AUDIO_ENABLE 0x000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define AUDIO_ENABLE 0x80000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define REG_DEF_AUDIO_GAIN 0x204
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define REG_GAIN_RAW_START 0x210
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define REG_GAIN_RAW_END 0x214
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define REG_GAIN_DB_START 0x218
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define REG_GAIN_DB_END 0x21c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define REG_SAMPLE_RATE_INQUIRY 0x280
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define REG_ISO_TX_CONFIG 0x300
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define SPEED_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define REG_SAMPLE_RATE 0x400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define RATE_48000 0x80000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define REG_GAIN 0x500
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define REG_MUTE 0x504
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define MAX_FRAMES_PER_PACKET 475
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define QUEUE_LENGTH 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct isight {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct fw_unit *unit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct fw_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u64 audio_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct snd_pcm_substream *pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct mutex mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct iso_packets_buffer buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct fw_iso_resources resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct fw_iso_context *context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) bool pcm_active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) bool pcm_running;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) bool first_packet;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) int packet_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u32 total_samples;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned int buffer_pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned int period_counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) s32 gain_min, gain_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) unsigned int gain_tlv[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct audio_payload {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) __be32 sample_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) __be32 signature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) __be32 sample_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) __be32 reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) __be16 samples[2 * MAX_FRAMES_PER_PACKET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) MODULE_DESCRIPTION("iSight audio driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static struct fw_iso_packet audio_packet = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .payload_length = sizeof(struct audio_payload),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .interrupt = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) .header_length = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static void isight_update_pointers(struct isight *isight, unsigned int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct snd_pcm_runtime *runtime = isight->pcm->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) unsigned int ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) smp_wmb(); /* update buffer data before buffer pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ptr = isight->buffer_pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ptr += count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (ptr >= runtime->buffer_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ptr -= runtime->buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) WRITE_ONCE(isight->buffer_pointer, ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) isight->period_counter += count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (isight->period_counter >= runtime->period_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) isight->period_counter -= runtime->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) snd_pcm_period_elapsed(isight->pcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static void isight_samples(struct isight *isight,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) const __be16 *samples, unsigned int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct snd_pcm_runtime *runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) unsigned int count1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (!READ_ONCE(isight->pcm_running))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) runtime = isight->pcm->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (isight->buffer_pointer + count <= runtime->buffer_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) memcpy(runtime->dma_area + isight->buffer_pointer * 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) samples, count * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) count1 = runtime->buffer_size - isight->buffer_pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) memcpy(runtime->dma_area + isight->buffer_pointer * 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) samples, count1 * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) samples += count1 * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) memcpy(runtime->dma_area, samples, (count - count1) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) isight_update_pointers(isight, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static void isight_pcm_abort(struct isight *isight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (READ_ONCE(isight->pcm_active))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) snd_pcm_stop_xrun(isight->pcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static void isight_dropped_samples(struct isight *isight, unsigned int total)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct snd_pcm_runtime *runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) u32 dropped;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) unsigned int count1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (!READ_ONCE(isight->pcm_running))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) runtime = isight->pcm->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) dropped = total - isight->total_samples;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (dropped < runtime->buffer_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (isight->buffer_pointer + dropped <= runtime->buffer_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) memset(runtime->dma_area + isight->buffer_pointer * 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 0, dropped * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) count1 = runtime->buffer_size - isight->buffer_pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) memset(runtime->dma_area + isight->buffer_pointer * 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 0, count1 * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) memset(runtime->dma_area, 0, (dropped - count1) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) isight_update_pointers(isight, dropped);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) isight_pcm_abort(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static void isight_packet(struct fw_iso_context *context, u32 cycle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) size_t header_length, void *header, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) struct isight *isight = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) const struct audio_payload *payload;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) unsigned int index, length, count, total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (isight->packet_index < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) index = isight->packet_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) payload = isight->buffer.packets[index].buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) length = be32_to_cpup(header) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (likely(length >= 16 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) count = be32_to_cpu(payload->sample_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (likely(count <= (length - 16) / 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) total = be32_to_cpu(payload->sample_total);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (unlikely(total != isight->total_samples)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (!isight->first_packet)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) isight_dropped_samples(isight, total);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) isight->first_packet = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) isight->total_samples = total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) isight_samples(isight, payload->samples, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) isight->total_samples += count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) err = fw_iso_context_queue(isight->context, &audio_packet,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) &isight->buffer.iso_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) isight->buffer.packets[index].offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) dev_err(&isight->unit->device, "queueing error: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) isight_pcm_abort(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) isight->packet_index = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) fw_iso_context_queue_flush(isight->context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (++index >= QUEUE_LENGTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) isight->packet_index = index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static int isight_connect(struct isight *isight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) int ch, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) __be32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) retry_after_bus_reset:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) ch = fw_iso_resources_allocate(&isight->resources,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) sizeof(struct audio_payload),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) isight->device->max_speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (ch < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) err = ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) err = snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) isight->audio_base + REG_ISO_TX_CONFIG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) &value, 4, FW_FIXED_GENERATION |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) isight->resources.generation);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (err == -EAGAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) fw_iso_resources_free(&isight->resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) goto retry_after_bus_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) } else if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) goto err_resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) err_resources:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) fw_iso_resources_free(&isight->resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) static int isight_open(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static const struct snd_pcm_hardware hardware = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .info = SNDRV_PCM_INFO_MMAP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) SNDRV_PCM_INFO_MMAP_VALID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) SNDRV_PCM_INFO_BATCH |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) SNDRV_PCM_INFO_BLOCK_TRANSFER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) .formats = SNDRV_PCM_FMTBIT_S16_BE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .rates = SNDRV_PCM_RATE_48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) .rate_min = 48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) .rate_max = 48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) .channels_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) .buffer_bytes_max = 4 * 1024 * 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) .period_bytes_min = MAX_FRAMES_PER_PACKET * 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) .period_bytes_max = 1024 * 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) .periods_min = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) .periods_max = UINT_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct isight *isight = substream->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) substream->runtime->hw = hardware;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return iso_packets_buffer_init(&isight->buffer, isight->unit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) QUEUE_LENGTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) sizeof(struct audio_payload),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) DMA_FROM_DEVICE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static int isight_close(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) struct isight *isight = substream->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) iso_packets_buffer_destroy(&isight->buffer, isight->unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static int isight_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct snd_pcm_hw_params *hw_params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) struct isight *isight = substream->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) WRITE_ONCE(isight->pcm_active, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static int reg_read(struct isight *isight, int offset, __be32 *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) isight->audio_base + offset, value, 4, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) static int reg_write(struct isight *isight, int offset, __be32 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) isight->audio_base + offset, &value, 4, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) static void isight_stop_streaming(struct isight *isight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) __be32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (!isight->context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) fw_iso_context_stop(isight->context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) fw_iso_context_destroy(isight->context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) isight->context = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) fw_iso_resources_free(&isight->resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) isight->audio_base + REG_AUDIO_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) &value, 4, FW_QUIET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) static int isight_hw_free(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) struct isight *isight = substream->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) WRITE_ONCE(isight->pcm_active, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) mutex_lock(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) isight_stop_streaming(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) mutex_unlock(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static int isight_start_streaming(struct isight *isight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (isight->context) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (isight->packet_index < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) isight_stop_streaming(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) err = isight_connect(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) goto err_resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) isight->context = fw_iso_context_create(isight->device->card,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) FW_ISO_CONTEXT_RECEIVE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) isight->resources.channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) isight->device->max_speed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 4, isight_packet, isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (IS_ERR(isight->context)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) err = PTR_ERR(isight->context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) isight->context = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) goto err_resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) for (i = 0; i < QUEUE_LENGTH; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) err = fw_iso_context_queue(isight->context, &audio_packet,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) &isight->buffer.iso_buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) isight->buffer.packets[i].offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) goto err_context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) isight->first_packet = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) isight->packet_index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) err = fw_iso_context_start(isight->context, -1, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) goto err_context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) err_context:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) fw_iso_context_destroy(isight->context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) isight->context = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) err_resources:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) fw_iso_resources_free(&isight->resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) reg_write(isight, REG_AUDIO_ENABLE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static int isight_prepare(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) struct isight *isight = substream->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) isight->buffer_pointer = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) isight->period_counter = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) mutex_lock(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) err = isight_start_streaming(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) mutex_unlock(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct isight *isight = substream->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) WRITE_ONCE(isight->pcm_running, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) WRITE_ONCE(isight->pcm_running, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) struct isight *isight = substream->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return READ_ONCE(isight->buffer_pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) static int isight_create_pcm(struct isight *isight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static const struct snd_pcm_ops ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) .open = isight_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) .close = isight_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) .hw_params = isight_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) .hw_free = isight_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) .prepare = isight_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) .trigger = isight_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) .pointer = isight_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) struct snd_pcm *pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) pcm->private_data = isight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) strcpy(pcm->name, "iSight");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) isight->pcm->ops = &ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static int isight_gain_info(struct snd_kcontrol *ctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) struct snd_ctl_elem_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) struct isight *isight = ctl->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) info->count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) info->value.integer.min = isight->gain_min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) info->value.integer.max = isight->gain_max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static int isight_gain_get(struct snd_kcontrol *ctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) struct snd_ctl_elem_value *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) struct isight *isight = ctl->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) __be32 gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) err = reg_read(isight, REG_GAIN, &gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) value->value.integer.value[0] = (s32)be32_to_cpu(gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) static int isight_gain_put(struct snd_kcontrol *ctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) struct snd_ctl_elem_value *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) struct isight *isight = ctl->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (value->value.integer.value[0] < isight->gain_min ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) value->value.integer.value[0] > isight->gain_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) return reg_write(isight, REG_GAIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) cpu_to_be32(value->value.integer.value[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static int isight_mute_get(struct snd_kcontrol *ctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) struct snd_ctl_elem_value *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct isight *isight = ctl->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) __be32 mute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) err = reg_read(isight, REG_MUTE, &mute);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) value->value.integer.value[0] = !mute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) static int isight_mute_put(struct snd_kcontrol *ctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) struct snd_ctl_elem_value *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) struct isight *isight = ctl->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return reg_write(isight, REG_MUTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) (__force __be32)!value->value.integer.value[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static int isight_create_mixer(struct isight *isight)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) static const struct snd_kcontrol_new gain_control = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) .name = "Mic Capture Volume",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) SNDRV_CTL_ELEM_ACCESS_TLV_READ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) .info = isight_gain_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) .get = isight_gain_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) .put = isight_gain_put,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) static const struct snd_kcontrol_new mute_control = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) .name = "Mic Capture Switch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) .info = snd_ctl_boolean_mono_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) .get = isight_mute_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) .put = isight_mute_put,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) __be32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) struct snd_kcontrol *ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) err = reg_read(isight, REG_GAIN_RAW_START, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) isight->gain_min = be32_to_cpu(value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) err = reg_read(isight, REG_GAIN_RAW_END, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) isight->gain_max = be32_to_cpu(value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) isight->gain_tlv[SNDRV_CTL_TLVO_TYPE] = SNDRV_CTL_TLVT_DB_MINMAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) isight->gain_tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(unsigned int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) err = reg_read(isight, REG_GAIN_DB_START, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) isight->gain_tlv[SNDRV_CTL_TLVO_DB_MINMAX_MIN] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) (s32)be32_to_cpu(value) * 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) err = reg_read(isight, REG_GAIN_DB_END, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) isight->gain_tlv[SNDRV_CTL_TLVO_DB_MINMAX_MAX] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) (s32)be32_to_cpu(value) * 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) ctl = snd_ctl_new1(&gain_control, isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (ctl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) ctl->tlv.p = isight->gain_tlv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) err = snd_ctl_add(isight->card, ctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) static void isight_card_free(struct snd_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) struct isight *isight = card->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) fw_iso_resources_destroy(&isight->resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) static u64 get_unit_base(struct fw_unit *unit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) struct fw_csr_iterator i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) int key, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) fw_csr_iterator_init(&i, unit->directory);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) while (fw_csr_iterator_next(&i, &key, &value))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) if (key == CSR_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) return CSR_REGISTER_BASE + value * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) static int isight_probe(struct fw_unit *unit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) const struct ieee1394_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) struct fw_device *fw_dev = fw_parent_device(unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) struct isight *isight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) sizeof(*isight), &card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) isight = card->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) isight->card = card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) mutex_init(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) isight->unit = fw_unit_get(unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) isight->device = fw_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) isight->audio_base = get_unit_base(unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) if (!isight->audio_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) dev_err(&unit->device, "audio unit base not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) err = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) fw_iso_resources_init(&isight->resources, unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) card->private_free = isight_card_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) strcpy(card->driver, "iSight");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) strcpy(card->shortname, "Apple iSight");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) snprintf(card->longname, sizeof(card->longname),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) "Apple iSight (GUID %08x%08x) at %s, S%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) fw_dev->config_rom[3], fw_dev->config_rom[4],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) dev_name(&unit->device), 100 << fw_dev->max_speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) strcpy(card->mixername, "iSight");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) err = isight_create_pcm(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) err = isight_create_mixer(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) err = snd_card_register(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) dev_set_drvdata(&unit->device, isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) snd_card_free(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) mutex_destroy(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) fw_unit_put(isight->unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) static void isight_bus_reset(struct fw_unit *unit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) struct isight *isight = dev_get_drvdata(&unit->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (fw_iso_resources_update(&isight->resources) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) isight_pcm_abort(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) mutex_lock(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) isight_stop_streaming(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) mutex_unlock(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) static void isight_remove(struct fw_unit *unit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) struct isight *isight = dev_get_drvdata(&unit->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) isight_pcm_abort(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) snd_card_disconnect(isight->card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) mutex_lock(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) isight_stop_streaming(isight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) mutex_unlock(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) // Block till all of ALSA character devices are released.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) snd_card_free(isight->card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) mutex_destroy(&isight->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) fw_unit_put(isight->unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) static const struct ieee1394_device_id isight_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) .match_flags = IEEE1394_MATCH_SPECIFIER_ID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) IEEE1394_MATCH_VERSION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) .specifier_id = OUI_APPLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) .version = SW_ISIGHT_AUDIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) MODULE_DEVICE_TABLE(ieee1394, isight_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static struct fw_driver isight_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) .name = KBUILD_MODNAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) .bus = &fw_bus_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) .probe = isight_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) .update = isight_bus_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) .remove = isight_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) .id_table = isight_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) static int __init alsa_isight_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) return driver_register(&isight_driver.driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) static void __exit alsa_isight_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) driver_unregister(&isight_driver.driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) module_init(alsa_isight_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) module_exit(alsa_isight_exit);