Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Apple iSight audio driver
0004  *
0005  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
0006  */
0007 
0008 #include <asm/byteorder.h>
0009 #include <linux/delay.h>
0010 #include <linux/device.h>
0011 #include <linux/firewire.h>
0012 #include <linux/firewire-constants.h>
0013 #include <linux/module.h>
0014 #include <linux/mod_devicetable.h>
0015 #include <linux/mutex.h>
0016 #include <linux/string.h>
0017 #include <sound/control.h>
0018 #include <sound/core.h>
0019 #include <sound/initval.h>
0020 #include <sound/pcm.h>
0021 #include <sound/tlv.h>
0022 #include "lib.h"
0023 #include "iso-resources.h"
0024 #include "packets-buffer.h"
0025 
0026 #define OUI_APPLE       0x000a27
0027 #define MODEL_APPLE_ISIGHT  0x000008
0028 #define SW_ISIGHT_AUDIO     0x000010
0029 
0030 #define REG_AUDIO_ENABLE    0x000
0031 #define  AUDIO_ENABLE       0x80000000
0032 #define REG_DEF_AUDIO_GAIN  0x204
0033 #define REG_GAIN_RAW_START  0x210
0034 #define REG_GAIN_RAW_END    0x214
0035 #define REG_GAIN_DB_START   0x218
0036 #define REG_GAIN_DB_END     0x21c
0037 #define REG_SAMPLE_RATE_INQUIRY 0x280
0038 #define REG_ISO_TX_CONFIG   0x300
0039 #define  SPEED_SHIFT        16
0040 #define REG_SAMPLE_RATE     0x400
0041 #define  RATE_48000     0x80000000
0042 #define REG_GAIN        0x500
0043 #define REG_MUTE        0x504
0044 
0045 #define MAX_FRAMES_PER_PACKET   475
0046 
0047 #define QUEUE_LENGTH        20
0048 
0049 struct isight {
0050     struct snd_card *card;
0051     struct fw_unit *unit;
0052     struct fw_device *device;
0053     u64 audio_base;
0054     struct snd_pcm_substream *pcm;
0055     struct mutex mutex;
0056     struct iso_packets_buffer buffer;
0057     struct fw_iso_resources resources;
0058     struct fw_iso_context *context;
0059     bool pcm_active;
0060     bool pcm_running;
0061     bool first_packet;
0062     int packet_index;
0063     u32 total_samples;
0064     unsigned int buffer_pointer;
0065     unsigned int period_counter;
0066     s32 gain_min, gain_max;
0067     unsigned int gain_tlv[4];
0068 };
0069 
0070 struct audio_payload {
0071     __be32 sample_count;
0072     __be32 signature;
0073     __be32 sample_total;
0074     __be32 reserved;
0075     __be16 samples[2 * MAX_FRAMES_PER_PACKET];
0076 };
0077 
0078 MODULE_DESCRIPTION("iSight audio driver");
0079 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
0080 MODULE_LICENSE("GPL v2");
0081 
0082 static struct fw_iso_packet audio_packet = {
0083     .payload_length = sizeof(struct audio_payload),
0084     .interrupt = 1,
0085     .header_length = 4,
0086 };
0087 
0088 static void isight_update_pointers(struct isight *isight, unsigned int count)
0089 {
0090     struct snd_pcm_runtime *runtime = isight->pcm->runtime;
0091     unsigned int ptr;
0092 
0093     smp_wmb(); /* update buffer data before buffer pointer */
0094 
0095     ptr = isight->buffer_pointer;
0096     ptr += count;
0097     if (ptr >= runtime->buffer_size)
0098         ptr -= runtime->buffer_size;
0099     WRITE_ONCE(isight->buffer_pointer, ptr);
0100 
0101     isight->period_counter += count;
0102     if (isight->period_counter >= runtime->period_size) {
0103         isight->period_counter -= runtime->period_size;
0104         snd_pcm_period_elapsed(isight->pcm);
0105     }
0106 }
0107 
0108 static void isight_samples(struct isight *isight,
0109                const __be16 *samples, unsigned int count)
0110 {
0111     struct snd_pcm_runtime *runtime;
0112     unsigned int count1;
0113 
0114     if (!READ_ONCE(isight->pcm_running))
0115         return;
0116 
0117     runtime = isight->pcm->runtime;
0118     if (isight->buffer_pointer + count <= runtime->buffer_size) {
0119         memcpy(runtime->dma_area + isight->buffer_pointer * 4,
0120                samples, count * 4);
0121     } else {
0122         count1 = runtime->buffer_size - isight->buffer_pointer;
0123         memcpy(runtime->dma_area + isight->buffer_pointer * 4,
0124                samples, count1 * 4);
0125         samples += count1 * 2;
0126         memcpy(runtime->dma_area, samples, (count - count1) * 4);
0127     }
0128 
0129     isight_update_pointers(isight, count);
0130 }
0131 
0132 static void isight_pcm_abort(struct isight *isight)
0133 {
0134     if (READ_ONCE(isight->pcm_active))
0135         snd_pcm_stop_xrun(isight->pcm);
0136 }
0137 
0138 static void isight_dropped_samples(struct isight *isight, unsigned int total)
0139 {
0140     struct snd_pcm_runtime *runtime;
0141     u32 dropped;
0142     unsigned int count1;
0143 
0144     if (!READ_ONCE(isight->pcm_running))
0145         return;
0146 
0147     runtime = isight->pcm->runtime;
0148     dropped = total - isight->total_samples;
0149     if (dropped < runtime->buffer_size) {
0150         if (isight->buffer_pointer + dropped <= runtime->buffer_size) {
0151             memset(runtime->dma_area + isight->buffer_pointer * 4,
0152                    0, dropped * 4);
0153         } else {
0154             count1 = runtime->buffer_size - isight->buffer_pointer;
0155             memset(runtime->dma_area + isight->buffer_pointer * 4,
0156                    0, count1 * 4);
0157             memset(runtime->dma_area, 0, (dropped - count1) * 4);
0158         }
0159         isight_update_pointers(isight, dropped);
0160     } else {
0161         isight_pcm_abort(isight);
0162     }
0163 }
0164 
0165 static void isight_packet(struct fw_iso_context *context, u32 cycle,
0166               size_t header_length, void *header, void *data)
0167 {
0168     struct isight *isight = data;
0169     const struct audio_payload *payload;
0170     unsigned int index, length, count, total;
0171     int err;
0172 
0173     if (isight->packet_index < 0)
0174         return;
0175     index = isight->packet_index;
0176     payload = isight->buffer.packets[index].buffer;
0177     length = be32_to_cpup(header) >> 16;
0178 
0179     if (likely(length >= 16 &&
0180            payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
0181         count = be32_to_cpu(payload->sample_count);
0182         if (likely(count <= (length - 16) / 4)) {
0183             total = be32_to_cpu(payload->sample_total);
0184             if (unlikely(total != isight->total_samples)) {
0185                 if (!isight->first_packet)
0186                     isight_dropped_samples(isight, total);
0187                 isight->first_packet = false;
0188                 isight->total_samples = total;
0189             }
0190 
0191             isight_samples(isight, payload->samples, count);
0192             isight->total_samples += count;
0193         }
0194     }
0195 
0196     err = fw_iso_context_queue(isight->context, &audio_packet,
0197                    &isight->buffer.iso_buffer,
0198                    isight->buffer.packets[index].offset);
0199     if (err < 0) {
0200         dev_err(&isight->unit->device, "queueing error: %d\n", err);
0201         isight_pcm_abort(isight);
0202         isight->packet_index = -1;
0203         return;
0204     }
0205     fw_iso_context_queue_flush(isight->context);
0206 
0207     if (++index >= QUEUE_LENGTH)
0208         index = 0;
0209     isight->packet_index = index;
0210 }
0211 
0212 static int isight_connect(struct isight *isight)
0213 {
0214     int ch, err;
0215     __be32 value;
0216 
0217 retry_after_bus_reset:
0218     ch = fw_iso_resources_allocate(&isight->resources,
0219                        sizeof(struct audio_payload),
0220                        isight->device->max_speed);
0221     if (ch < 0) {
0222         err = ch;
0223         goto error;
0224     }
0225 
0226     value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT));
0227     err = snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
0228                  isight->audio_base + REG_ISO_TX_CONFIG,
0229                  &value, 4, FW_FIXED_GENERATION |
0230                  isight->resources.generation);
0231     if (err == -EAGAIN) {
0232         fw_iso_resources_free(&isight->resources);
0233         goto retry_after_bus_reset;
0234     } else if (err < 0) {
0235         goto err_resources;
0236     }
0237 
0238     return 0;
0239 
0240 err_resources:
0241     fw_iso_resources_free(&isight->resources);
0242 error:
0243     return err;
0244 }
0245 
0246 static int isight_open(struct snd_pcm_substream *substream)
0247 {
0248     static const struct snd_pcm_hardware hardware = {
0249         .info = SNDRV_PCM_INFO_MMAP |
0250             SNDRV_PCM_INFO_MMAP_VALID |
0251             SNDRV_PCM_INFO_BATCH |
0252             SNDRV_PCM_INFO_INTERLEAVED |
0253             SNDRV_PCM_INFO_BLOCK_TRANSFER,
0254         .formats = SNDRV_PCM_FMTBIT_S16_BE,
0255         .rates = SNDRV_PCM_RATE_48000,
0256         .rate_min = 48000,
0257         .rate_max = 48000,
0258         .channels_min = 2,
0259         .channels_max = 2,
0260         .buffer_bytes_max = 4 * 1024 * 1024,
0261         .period_bytes_min = MAX_FRAMES_PER_PACKET * 4,
0262         .period_bytes_max = 1024 * 1024,
0263         .periods_min = 2,
0264         .periods_max = UINT_MAX,
0265     };
0266     struct isight *isight = substream->private_data;
0267 
0268     substream->runtime->hw = hardware;
0269 
0270     return iso_packets_buffer_init(&isight->buffer, isight->unit,
0271                        QUEUE_LENGTH,
0272                        sizeof(struct audio_payload),
0273                        DMA_FROM_DEVICE);
0274 }
0275 
0276 static int isight_close(struct snd_pcm_substream *substream)
0277 {
0278     struct isight *isight = substream->private_data;
0279 
0280     iso_packets_buffer_destroy(&isight->buffer, isight->unit);
0281 
0282     return 0;
0283 }
0284 
0285 static int isight_hw_params(struct snd_pcm_substream *substream,
0286                 struct snd_pcm_hw_params *hw_params)
0287 {
0288     struct isight *isight = substream->private_data;
0289 
0290     WRITE_ONCE(isight->pcm_active, true);
0291 
0292     return 0;
0293 }
0294 
0295 static int reg_read(struct isight *isight, int offset, __be32 *value)
0296 {
0297     return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
0298                   isight->audio_base + offset, value, 4, 0);
0299 }
0300 
0301 static int reg_write(struct isight *isight, int offset, __be32 value)
0302 {
0303     return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
0304                   isight->audio_base + offset, &value, 4, 0);
0305 }
0306 
0307 static void isight_stop_streaming(struct isight *isight)
0308 {
0309     __be32 value;
0310 
0311     if (!isight->context)
0312         return;
0313 
0314     fw_iso_context_stop(isight->context);
0315     fw_iso_context_destroy(isight->context);
0316     isight->context = NULL;
0317     fw_iso_resources_free(&isight->resources);
0318     value = 0;
0319     snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
0320                isight->audio_base + REG_AUDIO_ENABLE,
0321                &value, 4, FW_QUIET);
0322 }
0323 
0324 static int isight_hw_free(struct snd_pcm_substream *substream)
0325 {
0326     struct isight *isight = substream->private_data;
0327 
0328     WRITE_ONCE(isight->pcm_active, false);
0329 
0330     mutex_lock(&isight->mutex);
0331     isight_stop_streaming(isight);
0332     mutex_unlock(&isight->mutex);
0333 
0334     return 0;
0335 }
0336 
0337 static int isight_start_streaming(struct isight *isight)
0338 {
0339     unsigned int i;
0340     int err;
0341 
0342     if (isight->context) {
0343         if (isight->packet_index < 0)
0344             isight_stop_streaming(isight);
0345         else
0346             return 0;
0347     }
0348 
0349     err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000));
0350     if (err < 0)
0351         goto error;
0352 
0353     err = isight_connect(isight);
0354     if (err < 0)
0355         goto error;
0356 
0357     err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE));
0358     if (err < 0)
0359         goto err_resources;
0360 
0361     isight->context = fw_iso_context_create(isight->device->card,
0362                         FW_ISO_CONTEXT_RECEIVE,
0363                         isight->resources.channel,
0364                         isight->device->max_speed,
0365                         4, isight_packet, isight);
0366     if (IS_ERR(isight->context)) {
0367         err = PTR_ERR(isight->context);
0368         isight->context = NULL;
0369         goto err_resources;
0370     }
0371 
0372     for (i = 0; i < QUEUE_LENGTH; ++i) {
0373         err = fw_iso_context_queue(isight->context, &audio_packet,
0374                        &isight->buffer.iso_buffer,
0375                        isight->buffer.packets[i].offset);
0376         if (err < 0)
0377             goto err_context;
0378     }
0379 
0380     isight->first_packet = true;
0381     isight->packet_index = 0;
0382 
0383     err = fw_iso_context_start(isight->context, -1, 0,
0384                    FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
0385     if (err < 0)
0386         goto err_context;
0387 
0388     return 0;
0389 
0390 err_context:
0391     fw_iso_context_destroy(isight->context);
0392     isight->context = NULL;
0393 err_resources:
0394     fw_iso_resources_free(&isight->resources);
0395     reg_write(isight, REG_AUDIO_ENABLE, 0);
0396 error:
0397     return err;
0398 }
0399 
0400 static int isight_prepare(struct snd_pcm_substream *substream)
0401 {
0402     struct isight *isight = substream->private_data;
0403     int err;
0404 
0405     isight->buffer_pointer = 0;
0406     isight->period_counter = 0;
0407 
0408     mutex_lock(&isight->mutex);
0409     err = isight_start_streaming(isight);
0410     mutex_unlock(&isight->mutex);
0411 
0412     return err;
0413 }
0414 
0415 static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
0416 {
0417     struct isight *isight = substream->private_data;
0418 
0419     switch (cmd) {
0420     case SNDRV_PCM_TRIGGER_START:
0421         WRITE_ONCE(isight->pcm_running, true);
0422         break;
0423     case SNDRV_PCM_TRIGGER_STOP:
0424         WRITE_ONCE(isight->pcm_running, false);
0425         break;
0426     default:
0427         return -EINVAL;
0428     }
0429     return 0;
0430 }
0431 
0432 static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
0433 {
0434     struct isight *isight = substream->private_data;
0435 
0436     return READ_ONCE(isight->buffer_pointer);
0437 }
0438 
0439 static int isight_create_pcm(struct isight *isight)
0440 {
0441     static const struct snd_pcm_ops ops = {
0442         .open      = isight_open,
0443         .close     = isight_close,
0444         .hw_params = isight_hw_params,
0445         .hw_free   = isight_hw_free,
0446         .prepare   = isight_prepare,
0447         .trigger   = isight_trigger,
0448         .pointer   = isight_pointer,
0449     };
0450     struct snd_pcm *pcm;
0451     int err;
0452 
0453     err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
0454     if (err < 0)
0455         return err;
0456     pcm->private_data = isight;
0457     strcpy(pcm->name, "iSight");
0458     isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
0459     isight->pcm->ops = &ops;
0460     snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
0461 
0462     return 0;
0463 }
0464 
0465 static int isight_gain_info(struct snd_kcontrol *ctl,
0466                 struct snd_ctl_elem_info *info)
0467 {
0468     struct isight *isight = ctl->private_data;
0469 
0470     info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0471     info->count = 1;
0472     info->value.integer.min = isight->gain_min;
0473     info->value.integer.max = isight->gain_max;
0474 
0475     return 0;
0476 }
0477 
0478 static int isight_gain_get(struct snd_kcontrol *ctl,
0479                struct snd_ctl_elem_value *value)
0480 {
0481     struct isight *isight = ctl->private_data;
0482     __be32 gain;
0483     int err;
0484 
0485     err = reg_read(isight, REG_GAIN, &gain);
0486     if (err < 0)
0487         return err;
0488 
0489     value->value.integer.value[0] = (s32)be32_to_cpu(gain);
0490 
0491     return 0;
0492 }
0493 
0494 static int isight_gain_put(struct snd_kcontrol *ctl,
0495                struct snd_ctl_elem_value *value)
0496 {
0497     struct isight *isight = ctl->private_data;
0498 
0499     if (value->value.integer.value[0] < isight->gain_min ||
0500         value->value.integer.value[0] > isight->gain_max)
0501         return -EINVAL;
0502 
0503     return reg_write(isight, REG_GAIN,
0504              cpu_to_be32(value->value.integer.value[0]));
0505 }
0506 
0507 static int isight_mute_get(struct snd_kcontrol *ctl,
0508                struct snd_ctl_elem_value *value)
0509 {
0510     struct isight *isight = ctl->private_data;
0511     __be32 mute;
0512     int err;
0513 
0514     err = reg_read(isight, REG_MUTE, &mute);
0515     if (err < 0)
0516         return err;
0517 
0518     value->value.integer.value[0] = !mute;
0519 
0520     return 0;
0521 }
0522 
0523 static int isight_mute_put(struct snd_kcontrol *ctl,
0524                struct snd_ctl_elem_value *value)
0525 {
0526     struct isight *isight = ctl->private_data;
0527 
0528     return reg_write(isight, REG_MUTE,
0529              (__force __be32)!value->value.integer.value[0]);
0530 }
0531 
0532 static int isight_create_mixer(struct isight *isight)
0533 {
0534     static const struct snd_kcontrol_new gain_control = {
0535         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0536         .name = "Mic Capture Volume",
0537         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
0538               SNDRV_CTL_ELEM_ACCESS_TLV_READ,
0539         .info = isight_gain_info,
0540         .get = isight_gain_get,
0541         .put = isight_gain_put,
0542     };
0543     static const struct snd_kcontrol_new mute_control = {
0544         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0545         .name = "Mic Capture Switch",
0546         .info = snd_ctl_boolean_mono_info,
0547         .get = isight_mute_get,
0548         .put = isight_mute_put,
0549     };
0550     __be32 value;
0551     struct snd_kcontrol *ctl;
0552     int err;
0553 
0554     err = reg_read(isight, REG_GAIN_RAW_START, &value);
0555     if (err < 0)
0556         return err;
0557     isight->gain_min = be32_to_cpu(value);
0558 
0559     err = reg_read(isight, REG_GAIN_RAW_END, &value);
0560     if (err < 0)
0561         return err;
0562     isight->gain_max = be32_to_cpu(value);
0563 
0564     isight->gain_tlv[SNDRV_CTL_TLVO_TYPE] = SNDRV_CTL_TLVT_DB_MINMAX;
0565     isight->gain_tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(unsigned int);
0566 
0567     err = reg_read(isight, REG_GAIN_DB_START, &value);
0568     if (err < 0)
0569         return err;
0570     isight->gain_tlv[SNDRV_CTL_TLVO_DB_MINMAX_MIN] =
0571                         (s32)be32_to_cpu(value) * 100;
0572 
0573     err = reg_read(isight, REG_GAIN_DB_END, &value);
0574     if (err < 0)
0575         return err;
0576     isight->gain_tlv[SNDRV_CTL_TLVO_DB_MINMAX_MAX] =
0577                         (s32)be32_to_cpu(value) * 100;
0578 
0579     ctl = snd_ctl_new1(&gain_control, isight);
0580     if (ctl)
0581         ctl->tlv.p = isight->gain_tlv;
0582     err = snd_ctl_add(isight->card, ctl);
0583     if (err < 0)
0584         return err;
0585 
0586     err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight));
0587     if (err < 0)
0588         return err;
0589 
0590     return 0;
0591 }
0592 
0593 static void isight_card_free(struct snd_card *card)
0594 {
0595     struct isight *isight = card->private_data;
0596 
0597     fw_iso_resources_destroy(&isight->resources);
0598 }
0599 
0600 static u64 get_unit_base(struct fw_unit *unit)
0601 {
0602     struct fw_csr_iterator i;
0603     int key, value;
0604 
0605     fw_csr_iterator_init(&i, unit->directory);
0606     while (fw_csr_iterator_next(&i, &key, &value))
0607         if (key == CSR_OFFSET)
0608             return CSR_REGISTER_BASE + value * 4;
0609     return 0;
0610 }
0611 
0612 static int isight_probe(struct fw_unit *unit,
0613             const struct ieee1394_device_id *id)
0614 {
0615     struct fw_device *fw_dev = fw_parent_device(unit);
0616     struct snd_card *card;
0617     struct isight *isight;
0618     int err;
0619 
0620     err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
0621                sizeof(*isight), &card);
0622     if (err < 0)
0623         return err;
0624 
0625     isight = card->private_data;
0626     isight->card = card;
0627     mutex_init(&isight->mutex);
0628     isight->unit = fw_unit_get(unit);
0629     isight->device = fw_dev;
0630     isight->audio_base = get_unit_base(unit);
0631     if (!isight->audio_base) {
0632         dev_err(&unit->device, "audio unit base not found\n");
0633         err = -ENXIO;
0634         goto error;
0635     }
0636     fw_iso_resources_init(&isight->resources, unit);
0637 
0638     card->private_free = isight_card_free;
0639 
0640     strcpy(card->driver, "iSight");
0641     strcpy(card->shortname, "Apple iSight");
0642     snprintf(card->longname, sizeof(card->longname),
0643          "Apple iSight (GUID %08x%08x) at %s, S%d",
0644          fw_dev->config_rom[3], fw_dev->config_rom[4],
0645          dev_name(&unit->device), 100 << fw_dev->max_speed);
0646     strcpy(card->mixername, "iSight");
0647 
0648     err = isight_create_pcm(isight);
0649     if (err < 0)
0650         goto error;
0651 
0652     err = isight_create_mixer(isight);
0653     if (err < 0)
0654         goto error;
0655 
0656     err = snd_card_register(card);
0657     if (err < 0)
0658         goto error;
0659 
0660     dev_set_drvdata(&unit->device, isight);
0661 
0662     return 0;
0663 error:
0664     snd_card_free(card);
0665 
0666     mutex_destroy(&isight->mutex);
0667     fw_unit_put(isight->unit);
0668 
0669     return err;
0670 }
0671 
0672 static void isight_bus_reset(struct fw_unit *unit)
0673 {
0674     struct isight *isight = dev_get_drvdata(&unit->device);
0675 
0676     if (fw_iso_resources_update(&isight->resources) < 0) {
0677         isight_pcm_abort(isight);
0678 
0679         mutex_lock(&isight->mutex);
0680         isight_stop_streaming(isight);
0681         mutex_unlock(&isight->mutex);
0682     }
0683 }
0684 
0685 static void isight_remove(struct fw_unit *unit)
0686 {
0687     struct isight *isight = dev_get_drvdata(&unit->device);
0688 
0689     isight_pcm_abort(isight);
0690 
0691     snd_card_disconnect(isight->card);
0692 
0693     mutex_lock(&isight->mutex);
0694     isight_stop_streaming(isight);
0695     mutex_unlock(&isight->mutex);
0696 
0697     // Block till all of ALSA character devices are released.
0698     snd_card_free(isight->card);
0699 
0700     mutex_destroy(&isight->mutex);
0701     fw_unit_put(isight->unit);
0702 }
0703 
0704 static const struct ieee1394_device_id isight_id_table[] = {
0705     {
0706         .match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
0707                 IEEE1394_MATCH_VERSION,
0708         .specifier_id = OUI_APPLE,
0709         .version      = SW_ISIGHT_AUDIO,
0710     },
0711     { }
0712 };
0713 MODULE_DEVICE_TABLE(ieee1394, isight_id_table);
0714 
0715 static struct fw_driver isight_driver = {
0716     .driver   = {
0717         .owner  = THIS_MODULE,
0718         .name   = KBUILD_MODNAME,
0719         .bus    = &fw_bus_type,
0720     },
0721     .probe    = isight_probe,
0722     .update   = isight_bus_reset,
0723     .remove   = isight_remove,
0724     .id_table = isight_id_table,
0725 };
0726 
0727 static int __init alsa_isight_init(void)
0728 {
0729     return driver_register(&isight_driver.driver);
0730 }
0731 
0732 static void __exit alsa_isight_exit(void)
0733 {
0734     driver_unregister(&isight_driver.driver);
0735 }
0736 
0737 module_init(alsa_isight_init);
0738 module_exit(alsa_isight_exit);