xref: /linux/sound/firewire/isight.c (revision 28336be568bb473d16ba80db0801276fb4f1bbe5)
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 
49 struct 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 
70 struct 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 
78 MODULE_DESCRIPTION("iSight audio driver");
79 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
80 MODULE_LICENSE("GPL v2");
81 
82 static struct fw_iso_packet audio_packet = {
83 	.payload_length = sizeof(struct audio_payload),
84 	.interrupt = 1,
85 	.header_length = 4,
86 };
87 
88 static 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 
108 static 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 
132 static void isight_pcm_abort(struct isight *isight)
133 {
134 	if (READ_ONCE(isight->pcm_active))
135 		snd_pcm_stop_xrun(isight->pcm);
136 }
137 
138 static 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 
165 static 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 
212 static int isight_connect(struct isight *isight)
213 {
214 	int ch, err;
215 	__be32 value;
216 
217 retry_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 
240 err_resources:
241 	fw_iso_resources_free(&isight->resources);
242 error:
243 	return err;
244 }
245 
246 static 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 
276 static 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 
285 static 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 	int err;
290 
291 	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
292 	if (err < 0)
293 		return err;
294 
295 	WRITE_ONCE(isight->pcm_active, true);
296 
297 	return 0;
298 }
299 
300 static int reg_read(struct isight *isight, int offset, __be32 *value)
301 {
302 	return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
303 				  isight->audio_base + offset, value, 4, 0);
304 }
305 
306 static int reg_write(struct isight *isight, int offset, __be32 value)
307 {
308 	return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
309 				  isight->audio_base + offset, &value, 4, 0);
310 }
311 
312 static void isight_stop_streaming(struct isight *isight)
313 {
314 	__be32 value;
315 
316 	if (!isight->context)
317 		return;
318 
319 	fw_iso_context_stop(isight->context);
320 	fw_iso_context_destroy(isight->context);
321 	isight->context = NULL;
322 	fw_iso_resources_free(&isight->resources);
323 	value = 0;
324 	snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
325 			   isight->audio_base + REG_AUDIO_ENABLE,
326 			   &value, 4, FW_QUIET);
327 }
328 
329 static int isight_hw_free(struct snd_pcm_substream *substream)
330 {
331 	struct isight *isight = substream->private_data;
332 
333 	WRITE_ONCE(isight->pcm_active, false);
334 
335 	mutex_lock(&isight->mutex);
336 	isight_stop_streaming(isight);
337 	mutex_unlock(&isight->mutex);
338 
339 	return snd_pcm_lib_free_pages(substream);
340 }
341 
342 static int isight_start_streaming(struct isight *isight)
343 {
344 	unsigned int i;
345 	int err;
346 
347 	if (isight->context) {
348 		if (isight->packet_index < 0)
349 			isight_stop_streaming(isight);
350 		else
351 			return 0;
352 	}
353 
354 	err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000));
355 	if (err < 0)
356 		goto error;
357 
358 	err = isight_connect(isight);
359 	if (err < 0)
360 		goto error;
361 
362 	err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE));
363 	if (err < 0)
364 		goto err_resources;
365 
366 	isight->context = fw_iso_context_create(isight->device->card,
367 						FW_ISO_CONTEXT_RECEIVE,
368 						isight->resources.channel,
369 						isight->device->max_speed,
370 						4, isight_packet, isight);
371 	if (IS_ERR(isight->context)) {
372 		err = PTR_ERR(isight->context);
373 		isight->context = NULL;
374 		goto err_resources;
375 	}
376 
377 	for (i = 0; i < QUEUE_LENGTH; ++i) {
378 		err = fw_iso_context_queue(isight->context, &audio_packet,
379 					   &isight->buffer.iso_buffer,
380 					   isight->buffer.packets[i].offset);
381 		if (err < 0)
382 			goto err_context;
383 	}
384 
385 	isight->first_packet = true;
386 	isight->packet_index = 0;
387 
388 	err = fw_iso_context_start(isight->context, -1, 0,
389 				   FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
390 	if (err < 0)
391 		goto err_context;
392 
393 	return 0;
394 
395 err_context:
396 	fw_iso_context_destroy(isight->context);
397 	isight->context = NULL;
398 err_resources:
399 	fw_iso_resources_free(&isight->resources);
400 	reg_write(isight, REG_AUDIO_ENABLE, 0);
401 error:
402 	return err;
403 }
404 
405 static int isight_prepare(struct snd_pcm_substream *substream)
406 {
407 	struct isight *isight = substream->private_data;
408 	int err;
409 
410 	isight->buffer_pointer = 0;
411 	isight->period_counter = 0;
412 
413 	mutex_lock(&isight->mutex);
414 	err = isight_start_streaming(isight);
415 	mutex_unlock(&isight->mutex);
416 
417 	return err;
418 }
419 
420 static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
421 {
422 	struct isight *isight = substream->private_data;
423 
424 	switch (cmd) {
425 	case SNDRV_PCM_TRIGGER_START:
426 		WRITE_ONCE(isight->pcm_running, true);
427 		break;
428 	case SNDRV_PCM_TRIGGER_STOP:
429 		WRITE_ONCE(isight->pcm_running, false);
430 		break;
431 	default:
432 		return -EINVAL;
433 	}
434 	return 0;
435 }
436 
437 static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
438 {
439 	struct isight *isight = substream->private_data;
440 
441 	return READ_ONCE(isight->buffer_pointer);
442 }
443 
444 static int isight_create_pcm(struct isight *isight)
445 {
446 	static const struct snd_pcm_ops ops = {
447 		.open      = isight_open,
448 		.close     = isight_close,
449 		.ioctl     = snd_pcm_lib_ioctl,
450 		.hw_params = isight_hw_params,
451 		.hw_free   = isight_hw_free,
452 		.prepare   = isight_prepare,
453 		.trigger   = isight_trigger,
454 		.pointer   = isight_pointer,
455 	};
456 	struct snd_pcm *pcm;
457 	int err;
458 
459 	err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
460 	if (err < 0)
461 		return err;
462 	pcm->private_data = isight;
463 	strcpy(pcm->name, "iSight");
464 	isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
465 	isight->pcm->ops = &ops;
466 	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
467 					      NULL, 0, 0);
468 
469 	return 0;
470 }
471 
472 static int isight_gain_info(struct snd_kcontrol *ctl,
473 			    struct snd_ctl_elem_info *info)
474 {
475 	struct isight *isight = ctl->private_data;
476 
477 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
478 	info->count = 1;
479 	info->value.integer.min = isight->gain_min;
480 	info->value.integer.max = isight->gain_max;
481 
482 	return 0;
483 }
484 
485 static int isight_gain_get(struct snd_kcontrol *ctl,
486 			   struct snd_ctl_elem_value *value)
487 {
488 	struct isight *isight = ctl->private_data;
489 	__be32 gain;
490 	int err;
491 
492 	err = reg_read(isight, REG_GAIN, &gain);
493 	if (err < 0)
494 		return err;
495 
496 	value->value.integer.value[0] = (s32)be32_to_cpu(gain);
497 
498 	return 0;
499 }
500 
501 static int isight_gain_put(struct snd_kcontrol *ctl,
502 			   struct snd_ctl_elem_value *value)
503 {
504 	struct isight *isight = ctl->private_data;
505 
506 	if (value->value.integer.value[0] < isight->gain_min ||
507 	    value->value.integer.value[0] > isight->gain_max)
508 		return -EINVAL;
509 
510 	return reg_write(isight, REG_GAIN,
511 			 cpu_to_be32(value->value.integer.value[0]));
512 }
513 
514 static int isight_mute_get(struct snd_kcontrol *ctl,
515 			   struct snd_ctl_elem_value *value)
516 {
517 	struct isight *isight = ctl->private_data;
518 	__be32 mute;
519 	int err;
520 
521 	err = reg_read(isight, REG_MUTE, &mute);
522 	if (err < 0)
523 		return err;
524 
525 	value->value.integer.value[0] = !mute;
526 
527 	return 0;
528 }
529 
530 static int isight_mute_put(struct snd_kcontrol *ctl,
531 			   struct snd_ctl_elem_value *value)
532 {
533 	struct isight *isight = ctl->private_data;
534 
535 	return reg_write(isight, REG_MUTE,
536 			 (__force __be32)!value->value.integer.value[0]);
537 }
538 
539 static int isight_create_mixer(struct isight *isight)
540 {
541 	static const struct snd_kcontrol_new gain_control = {
542 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
543 		.name = "Mic Capture Volume",
544 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
545 			  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
546 		.info = isight_gain_info,
547 		.get = isight_gain_get,
548 		.put = isight_gain_put,
549 	};
550 	static const struct snd_kcontrol_new mute_control = {
551 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
552 		.name = "Mic Capture Switch",
553 		.info = snd_ctl_boolean_mono_info,
554 		.get = isight_mute_get,
555 		.put = isight_mute_put,
556 	};
557 	__be32 value;
558 	struct snd_kcontrol *ctl;
559 	int err;
560 
561 	err = reg_read(isight, REG_GAIN_RAW_START, &value);
562 	if (err < 0)
563 		return err;
564 	isight->gain_min = be32_to_cpu(value);
565 
566 	err = reg_read(isight, REG_GAIN_RAW_END, &value);
567 	if (err < 0)
568 		return err;
569 	isight->gain_max = be32_to_cpu(value);
570 
571 	isight->gain_tlv[SNDRV_CTL_TLVO_TYPE] = SNDRV_CTL_TLVT_DB_MINMAX;
572 	isight->gain_tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(unsigned int);
573 
574 	err = reg_read(isight, REG_GAIN_DB_START, &value);
575 	if (err < 0)
576 		return err;
577 	isight->gain_tlv[SNDRV_CTL_TLVO_DB_MINMAX_MIN] =
578 						(s32)be32_to_cpu(value) * 100;
579 
580 	err = reg_read(isight, REG_GAIN_DB_END, &value);
581 	if (err < 0)
582 		return err;
583 	isight->gain_tlv[SNDRV_CTL_TLVO_DB_MINMAX_MAX] =
584 						(s32)be32_to_cpu(value) * 100;
585 
586 	ctl = snd_ctl_new1(&gain_control, isight);
587 	if (ctl)
588 		ctl->tlv.p = isight->gain_tlv;
589 	err = snd_ctl_add(isight->card, ctl);
590 	if (err < 0)
591 		return err;
592 
593 	err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight));
594 	if (err < 0)
595 		return err;
596 
597 	return 0;
598 }
599 
600 static void isight_card_free(struct snd_card *card)
601 {
602 	struct isight *isight = card->private_data;
603 
604 	fw_iso_resources_destroy(&isight->resources);
605 }
606 
607 static u64 get_unit_base(struct fw_unit *unit)
608 {
609 	struct fw_csr_iterator i;
610 	int key, value;
611 
612 	fw_csr_iterator_init(&i, unit->directory);
613 	while (fw_csr_iterator_next(&i, &key, &value))
614 		if (key == CSR_OFFSET)
615 			return CSR_REGISTER_BASE + value * 4;
616 	return 0;
617 }
618 
619 static int isight_probe(struct fw_unit *unit,
620 			const struct ieee1394_device_id *id)
621 {
622 	struct fw_device *fw_dev = fw_parent_device(unit);
623 	struct snd_card *card;
624 	struct isight *isight;
625 	int err;
626 
627 	err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
628 			   sizeof(*isight), &card);
629 	if (err < 0)
630 		return err;
631 
632 	isight = card->private_data;
633 	isight->card = card;
634 	mutex_init(&isight->mutex);
635 	isight->unit = fw_unit_get(unit);
636 	isight->device = fw_dev;
637 	isight->audio_base = get_unit_base(unit);
638 	if (!isight->audio_base) {
639 		dev_err(&unit->device, "audio unit base not found\n");
640 		err = -ENXIO;
641 		goto error;
642 	}
643 	fw_iso_resources_init(&isight->resources, unit);
644 
645 	card->private_free = isight_card_free;
646 
647 	strcpy(card->driver, "iSight");
648 	strcpy(card->shortname, "Apple iSight");
649 	snprintf(card->longname, sizeof(card->longname),
650 		 "Apple iSight (GUID %08x%08x) at %s, S%d",
651 		 fw_dev->config_rom[3], fw_dev->config_rom[4],
652 		 dev_name(&unit->device), 100 << fw_dev->max_speed);
653 	strcpy(card->mixername, "iSight");
654 
655 	err = isight_create_pcm(isight);
656 	if (err < 0)
657 		goto error;
658 
659 	err = isight_create_mixer(isight);
660 	if (err < 0)
661 		goto error;
662 
663 	err = snd_card_register(card);
664 	if (err < 0)
665 		goto error;
666 
667 	dev_set_drvdata(&unit->device, isight);
668 
669 	return 0;
670 error:
671 	snd_card_free(card);
672 
673 	mutex_destroy(&isight->mutex);
674 	fw_unit_put(isight->unit);
675 
676 	return err;
677 }
678 
679 static void isight_bus_reset(struct fw_unit *unit)
680 {
681 	struct isight *isight = dev_get_drvdata(&unit->device);
682 
683 	if (fw_iso_resources_update(&isight->resources) < 0) {
684 		isight_pcm_abort(isight);
685 
686 		mutex_lock(&isight->mutex);
687 		isight_stop_streaming(isight);
688 		mutex_unlock(&isight->mutex);
689 	}
690 }
691 
692 static void isight_remove(struct fw_unit *unit)
693 {
694 	struct isight *isight = dev_get_drvdata(&unit->device);
695 
696 	isight_pcm_abort(isight);
697 
698 	snd_card_disconnect(isight->card);
699 
700 	mutex_lock(&isight->mutex);
701 	isight_stop_streaming(isight);
702 	mutex_unlock(&isight->mutex);
703 
704 	// Block till all of ALSA character devices are released.
705 	snd_card_free(isight->card);
706 
707 	mutex_destroy(&isight->mutex);
708 	fw_unit_put(isight->unit);
709 }
710 
711 static const struct ieee1394_device_id isight_id_table[] = {
712 	{
713 		.match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
714 				IEEE1394_MATCH_VERSION,
715 		.specifier_id = OUI_APPLE,
716 		.version      = SW_ISIGHT_AUDIO,
717 	},
718 	{ }
719 };
720 MODULE_DEVICE_TABLE(ieee1394, isight_id_table);
721 
722 static struct fw_driver isight_driver = {
723 	.driver   = {
724 		.owner	= THIS_MODULE,
725 		.name	= KBUILD_MODNAME,
726 		.bus	= &fw_bus_type,
727 	},
728 	.probe    = isight_probe,
729 	.update   = isight_bus_reset,
730 	.remove   = isight_remove,
731 	.id_table = isight_id_table,
732 };
733 
734 static int __init alsa_isight_init(void)
735 {
736 	return driver_register(&isight_driver.driver);
737 }
738 
739 static void __exit alsa_isight_exit(void)
740 {
741 	driver_unregister(&isight_driver.driver);
742 }
743 
744 module_init(alsa_isight_init);
745 module_exit(alsa_isight_exit);
746