cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

isight.c (17896B)


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