blob: 1a8da2614db66a981ca0861121fba242e250cf53 [file] [log] [blame]
Clemens Ladisch3a691b22011-05-11 10:44:51 +02001/*
2 * Apple iSight audio driver
3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * Licensed under the terms of the GNU General Public License, version 2.
6 */
7
8#include <linux/delay.h>
9#include <linux/device.h>
10#include <linux/firewire.h>
11#include <linux/firewire-constants.h>
12#include <linux/module.h>
13#include <linux/mod_devicetable.h>
14#include <linux/mutex.h>
15#include <linux/string.h>
16#include <sound/control.h>
17#include <sound/core.h>
18#include <sound/initval.h>
19#include <sound/pcm.h>
20#include <sound/tlv.h>
21#include "lib.h"
22#include "iso-resources.h"
23#include "packets-buffer.h"
24
25#define OUI_APPLE 0x000a27
26#define MODEL_APPLE_ISIGHT 0x000008
27#define SW_ISIGHT_AUDIO 0x000010
28
29#define REG_AUDIO_ENABLE 0x000
30#define AUDIO_ENABLE 0x80000000
31#define REG_DEF_AUDIO_GAIN 0x204
32#define REG_GAIN_RAW_START 0x210
33#define REG_GAIN_RAW_END 0x214
34#define REG_GAIN_DB_START 0x218
35#define REG_GAIN_DB_END 0x21c
36#define REG_SAMPLE_RATE_INQUIRY 0x280
37#define REG_ISO_TX_CONFIG 0x300
38#define SPEED_SHIFT 16
39#define REG_SAMPLE_RATE 0x400
40#define RATE_48000 0x80000000
41#define REG_GAIN 0x500
42#define REG_MUTE 0x504
43
44#define MAX_FRAMES_PER_PACKET 475
45
46#define QUEUE_LENGTH 20
47
48struct isight {
49 struct snd_card *card;
50 struct fw_unit *unit;
51 struct fw_device *device;
52 u64 audio_base;
53 struct fw_address_handler iris_handler;
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;
Clemens Ladisch03c29682011-05-11 10:47:30 +020059 bool pcm_active;
Clemens Ladisch3a691b22011-05-11 10:44:51 +020060 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,
Clemens Ladischf2934cd2011-05-11 10:49:02 +020085 .header_length = 4,
Clemens Ladisch3a691b22011-05-11 10:44:51 +020086};
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 ACCESS_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 (!ACCESS_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 unsigned long flags;
135
Clemens Ladisch03c29682011-05-11 10:47:30 +0200136 if (ACCESS_ONCE(isight->pcm_active)) {
137 snd_pcm_stream_lock_irqsave(isight->pcm, flags);
138 if (snd_pcm_running(isight->pcm))
139 snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN);
140 snd_pcm_stream_unlock_irqrestore(isight->pcm, flags);
141 }
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200142}
143
144static void isight_dropped_samples(struct isight *isight, unsigned int total)
145{
146 struct snd_pcm_runtime *runtime;
147 u32 dropped;
148 unsigned int count1;
149
150 if (!ACCESS_ONCE(isight->pcm_running))
151 return;
152
153 runtime = isight->pcm->runtime;
154 dropped = total - isight->total_samples;
155 if (dropped < runtime->buffer_size) {
156 if (isight->buffer_pointer + dropped <= runtime->buffer_size) {
157 memset(runtime->dma_area + isight->buffer_pointer * 4,
158 0, dropped * 4);
159 } else {
160 count1 = runtime->buffer_size - isight->buffer_pointer;
161 memset(runtime->dma_area + isight->buffer_pointer * 4,
162 0, count1 * 4);
163 memset(runtime->dma_area, 0, (dropped - count1) * 4);
164 }
165 isight_update_pointers(isight, dropped);
166 } else {
167 isight_pcm_abort(isight);
168 }
169}
170
171static void isight_packet(struct fw_iso_context *context, u32 cycle,
172 size_t header_length, void *header, void *data)
173{
174 struct isight *isight = data;
175 const struct audio_payload *payload;
176 unsigned int index, length, count, total;
177 int err;
178
179 if (isight->packet_index < 0)
180 return;
181 index = isight->packet_index;
182 payload = isight->buffer.packets[index].buffer;
183 length = be32_to_cpup(header) >> 16;
184
185 if (likely(length >= 16 &&
186 payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
187 count = be32_to_cpu(payload->sample_count);
188 if (likely(count <= (length - 16) / 4)) {
189 total = be32_to_cpu(payload->sample_total);
190 if (unlikely(total != isight->total_samples)) {
191 if (!isight->first_packet)
192 isight_dropped_samples(isight, total);
193 isight->first_packet = false;
194 isight->total_samples = total;
195 }
196
197 isight_samples(isight, payload->samples, count);
198 isight->total_samples += count;
199 }
200 }
201
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200202 err = fw_iso_context_queue(isight->context, &audio_packet,
203 &isight->buffer.iso_buffer,
204 isight->buffer.packets[index].offset);
205 if (err < 0) {
206 dev_err(&isight->unit->device, "queueing error: %d\n", err);
207 isight_pcm_abort(isight);
208 isight->packet_index = -1;
209 return;
210 }
211
Clemens Ladisch898732d2011-05-11 10:48:24 +0200212 if (++index >= QUEUE_LENGTH)
213 index = 0;
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200214 isight->packet_index = index;
215}
216
217static int isight_connect(struct isight *isight)
218{
219 int ch, err, rcode, errors = 0;
220 __be32 value;
221
222retry_after_bus_reset:
223 ch = fw_iso_resources_allocate(&isight->resources,
224 sizeof(struct audio_payload),
225 isight->device->max_speed);
226 if (ch < 0) {
227 err = ch;
228 goto error;
229 }
230
231 value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT));
232 for (;;) {
233 rcode = fw_run_transaction(
234 isight->device->card,
235 TCODE_WRITE_QUADLET_REQUEST,
236 isight->device->node_id,
237 isight->resources.generation,
238 isight->device->max_speed,
239 isight->audio_base + REG_ISO_TX_CONFIG,
240 &value, 4);
241 if (rcode == RCODE_COMPLETE) {
242 return 0;
243 } else if (rcode == RCODE_GENERATION) {
244 fw_iso_resources_free(&isight->resources);
245 goto retry_after_bus_reset;
246 } else if (rcode_is_permanent_error(rcode) || ++errors >= 3) {
247 err = -EIO;
248 goto err_resources;
249 }
250 msleep(5);
251 }
252
253err_resources:
254 fw_iso_resources_free(&isight->resources);
255error:
256 return err;
257}
258
259static int isight_open(struct snd_pcm_substream *substream)
260{
261 static const struct snd_pcm_hardware hardware = {
262 .info = SNDRV_PCM_INFO_MMAP |
263 SNDRV_PCM_INFO_MMAP_VALID |
264 SNDRV_PCM_INFO_BATCH |
265 SNDRV_PCM_INFO_INTERLEAVED |
266 SNDRV_PCM_INFO_BLOCK_TRANSFER,
267 .formats = SNDRV_PCM_FMTBIT_S16_BE,
268 .rates = SNDRV_PCM_RATE_48000,
269 .rate_min = 48000,
270 .rate_max = 48000,
271 .channels_min = 2,
272 .channels_max = 2,
273 .buffer_bytes_max = 4 * 1024 * 1024,
274 .period_bytes_min = MAX_FRAMES_PER_PACKET * 4,
275 .period_bytes_max = 1024 * 1024,
276 .periods_min = 2,
277 .periods_max = UINT_MAX,
278 };
279 struct isight *isight = substream->private_data;
280
281 substream->runtime->hw = hardware;
282
283 return iso_packets_buffer_init(&isight->buffer, isight->unit,
284 QUEUE_LENGTH,
285 sizeof(struct audio_payload),
286 DMA_FROM_DEVICE);
287}
288
289static int isight_close(struct snd_pcm_substream *substream)
290{
291 struct isight *isight = substream->private_data;
292
293 iso_packets_buffer_destroy(&isight->buffer, isight->unit);
294
295 return 0;
296}
297
298static int isight_hw_params(struct snd_pcm_substream *substream,
299 struct snd_pcm_hw_params *hw_params)
300{
Clemens Ladisch03c29682011-05-11 10:47:30 +0200301 struct isight *isight = substream->private_data;
302 int err;
303
304 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
305 params_buffer_bytes(hw_params));
306 if (err < 0)
307 return err;
308
309 ACCESS_ONCE(isight->pcm_active) = true;
310
311 return 0;
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200312}
313
314static void isight_stop_streaming(struct isight *isight)
315{
316 __be32 value;
317
318 if (!isight->context)
319 return;
320
321 fw_iso_context_stop(isight->context);
322 fw_iso_context_destroy(isight->context);
323 isight->context = NULL;
324
325 value = 0;
326 snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
327 isight->audio_base + REG_AUDIO_ENABLE,
328 &value, 4);
329
330 fw_iso_resources_free(&isight->resources);
331}
332
333static int isight_hw_free(struct snd_pcm_substream *substream)
334{
335 struct isight *isight = substream->private_data;
336
Clemens Ladisch03c29682011-05-11 10:47:30 +0200337 ACCESS_ONCE(isight->pcm_active) = false;
338
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200339 mutex_lock(&isight->mutex);
340 isight_stop_streaming(isight);
341 mutex_unlock(&isight->mutex);
342
343 return snd_pcm_lib_free_vmalloc_buffer(substream);
344}
345
346static int isight_start_streaming(struct isight *isight)
347{
Stefan Richter8839eed2011-05-11 10:49:58 +0200348 __be32 value;
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200349 unsigned int i;
350 int err;
351
352 if (isight->context) {
353 if (isight->packet_index < 0)
354 isight_stop_streaming(isight);
355 else
356 return 0;
357 }
358
Stefan Richter8839eed2011-05-11 10:49:58 +0200359 value = cpu_to_be32(RATE_48000);
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200360 err = snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
361 isight->audio_base + REG_SAMPLE_RATE,
Stefan Richter8839eed2011-05-11 10:49:58 +0200362 &value, 4);
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200363 if (err < 0)
364 return err;
365
366 err = isight_connect(isight);
367 if (err < 0)
368 goto error;
369
Stefan Richter8839eed2011-05-11 10:49:58 +0200370 value = cpu_to_be32(AUDIO_ENABLE);
371 err = snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
372 isight->audio_base + REG_AUDIO_ENABLE,
373 &value, 4);
374 if (err < 0)
375 goto err_resources;
376
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200377 isight->context = fw_iso_context_create(isight->device->card,
378 FW_ISO_CONTEXT_RECEIVE,
379 isight->resources.channel,
380 isight->device->max_speed,
381 4, isight_packet, isight);
382 if (IS_ERR(isight->context)) {
383 err = PTR_ERR(isight->context);
384 isight->context = NULL;
385 goto err_resources;
386 }
387
388 for (i = 0; i < QUEUE_LENGTH; ++i) {
389 err = fw_iso_context_queue(isight->context, &audio_packet,
390 &isight->buffer.iso_buffer,
391 isight->buffer.packets[i].offset);
392 if (err < 0)
393 goto err_context;
394 }
395
396 isight->first_packet = true;
397 isight->packet_index = 0;
398
399 err = fw_iso_context_start(isight->context, -1, 0,
400 FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
401 if (err < 0)
402 goto err_context;
403
404 return 0;
405
406err_context:
407 fw_iso_context_destroy(isight->context);
408 isight->context = NULL;
409err_resources:
Stefan Richter8839eed2011-05-11 10:49:58 +0200410 value = 0;
411 snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
412 isight->audio_base + REG_AUDIO_ENABLE,
413 &value, 4);
Clemens Ladisch3a691b22011-05-11 10:44:51 +0200414 fw_iso_resources_free(&isight->resources);
415error:
416 return err;
417}
418
419static int isight_prepare(struct snd_pcm_substream *substream)
420{
421 struct isight *isight = substream->private_data;
422 int err;
423
424 isight->buffer_pointer = 0;
425 isight->period_counter = 0;
426
427 mutex_lock(&isight->mutex);
428 err = isight_start_streaming(isight);
429 mutex_unlock(&isight->mutex);
430
431 return err;
432}
433
434static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
435{
436 struct isight *isight = substream->private_data;
437
438 switch (cmd) {
439 case SNDRV_PCM_TRIGGER_START:
440 ACCESS_ONCE(isight->pcm_running) = true;
441 break;
442 case SNDRV_PCM_TRIGGER_STOP:
443 ACCESS_ONCE(isight->pcm_running) = false;
444 break;
445 default:
446 return -EINVAL;
447 }
448 return 0;
449}
450
451static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
452{
453 struct isight *isight = substream->private_data;
454
455 return ACCESS_ONCE(isight->buffer_pointer);
456}
457
458static int isight_create_pcm(struct isight *isight)
459{
460 static struct snd_pcm_ops ops = {
461 .open = isight_open,
462 .close = isight_close,
463 .ioctl = snd_pcm_lib_ioctl,
464 .hw_params = isight_hw_params,
465 .hw_free = isight_hw_free,
466 .prepare = isight_prepare,
467 .trigger = isight_trigger,
468 .pointer = isight_pointer,
469 .page = snd_pcm_lib_get_vmalloc_page,
470 .mmap = snd_pcm_lib_mmap_vmalloc,
471 };
472 struct snd_pcm *pcm;
473 int err;
474
475 err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
476 if (err < 0)
477 return err;
478 pcm->private_data = isight;
479 strcpy(pcm->name, "iSight");
480 isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
481 isight->pcm->ops = &ops;
482
483 return 0;
484}
485
486static int isight_gain_info(struct snd_kcontrol *ctl,
487 struct snd_ctl_elem_info *info)
488{
489 struct isight *isight = ctl->private_data;
490
491 info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
492 info->count = 1;
493 info->value.integer.min = isight->gain_min;
494 info->value.integer.max = isight->gain_max;
495
496 return 0;
497}
498
499static int isight_gain_get(struct snd_kcontrol *ctl,
500 struct snd_ctl_elem_value *value)
501{
502 struct isight *isight = ctl->private_data;
503 __be32 gain;
504 int err;
505
506 err = snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
507 isight->audio_base + REG_GAIN, &gain, 4);
508 if (err < 0)
509 return err;
510
511 value->value.integer.value[0] = (s32)be32_to_cpu(gain);
512
513 return 0;
514}
515
516static int isight_gain_put(struct snd_kcontrol *ctl,
517 struct snd_ctl_elem_value *value)
518{
519 struct isight *isight = ctl->private_data;
520 __be32 gain;
521
522 if (value->value.integer.value[0] < isight->gain_min ||
523 value->value.integer.value[0] > isight->gain_max)
524 return -EINVAL;
525
526 gain = cpu_to_be32(value->value.integer.value[0]);
527 return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
528 isight->audio_base + REG_GAIN, &gain, 4);
529}
530
531static int isight_mute_get(struct snd_kcontrol *ctl,
532 struct snd_ctl_elem_value *value)
533{
534 struct isight *isight = ctl->private_data;
535 __be32 mute;
536 int err;
537
538 err = snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
539 isight->audio_base + REG_MUTE, &mute, 4);
540 if (err < 0)
541 return err;
542
543 value->value.integer.value[0] = !mute;
544
545 return 0;
546}
547
548static int isight_mute_put(struct snd_kcontrol *ctl,
549 struct snd_ctl_elem_value *value)
550{
551 struct isight *isight = ctl->private_data;
552 __be32 mute;
553
554 mute = (__force __be32)!value->value.integer.value[0];
555 return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
556 isight->audio_base + REG_MUTE, &mute, 4);
557}
558
559static int isight_create_mixer(struct isight *isight)
560{
561 static const struct snd_kcontrol_new gain_control = {
562 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
563 .name = "Mic Capture Volume",
564 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
565 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
566 .info = isight_gain_info,
567 .get = isight_gain_get,
568 .put = isight_gain_put,
569 };
570 static const struct snd_kcontrol_new mute_control = {
571 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
572 .name = "Mic Capture Switch",
573 .info = snd_ctl_boolean_mono_info,
574 .get = isight_mute_get,
575 .put = isight_mute_put,
576 };
577 __be32 value;
578 struct snd_kcontrol *ctl;
579 int err;
580
581 err = snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
582 isight->audio_base + REG_GAIN_RAW_START,
583 &value, 4);
584 if (err < 0)
585 return err;
586 isight->gain_min = be32_to_cpu(value);
587
588 err = snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
589 isight->audio_base + REG_GAIN_RAW_END,
590 &value, 4);
591 if (err < 0)
592 return err;
593 isight->gain_max = be32_to_cpu(value);
594
595 isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX;
596 isight->gain_tlv[1] = 2 * sizeof(unsigned int);
597 err = snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
598 isight->audio_base + REG_GAIN_DB_START,
599 &value, 4);
600 if (err < 0)
601 return err;
602 isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100;
603 err = snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
604 isight->audio_base + REG_GAIN_DB_END,
605 &value, 4);
606 if (err < 0)
607 return err;
608 isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100;
609
610 ctl = snd_ctl_new1(&gain_control, isight);
611 if (ctl)
612 ctl->tlv.p = isight->gain_tlv;
613 err = snd_ctl_add(isight->card, ctl);
614 if (err < 0)
615 return err;
616
617 err = snd_ctl_add(isight->card, snd_ctl_new1(&mute_control, isight));
618 if (err < 0)
619 return err;
620
621 return 0;
622}
623
624static void isight_card_free(struct snd_card *card)
625{
626 struct isight *isight = card->private_data;
627
628 fw_iso_resources_destroy(&isight->resources);
629 fw_unit_put(isight->unit);
630 fw_device_put(isight->device);
631 mutex_destroy(&isight->mutex);
632}
633
634static u64 get_unit_base(struct fw_unit *unit)
635{
636 struct fw_csr_iterator i;
637 int key, value;
638
639 fw_csr_iterator_init(&i, unit->directory);
640 while (fw_csr_iterator_next(&i, &key, &value))
641 if (key == CSR_OFFSET)
642 return CSR_REGISTER_BASE + value * 4;
643 return 0;
644}
645
646static int isight_probe(struct device *unit_dev)
647{
648 struct fw_unit *unit = fw_unit(unit_dev);
649 struct fw_device *fw_dev = fw_parent_device(unit);
650 struct snd_card *card;
651 struct isight *isight;
652 int err;
653
654 err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
655 if (err < 0)
656 return err;
657 snd_card_set_dev(card, unit_dev);
658
659 isight = card->private_data;
660 isight->card = card;
661 mutex_init(&isight->mutex);
662 isight->unit = fw_unit_get(unit);
663 isight->device = fw_device_get(fw_dev);
664 isight->audio_base = get_unit_base(unit);
665 if (!isight->audio_base) {
666 dev_err(&unit->device, "audio unit base not found\n");
667 err = -ENXIO;
668 goto err_unit;
669 }
670 fw_iso_resources_init(&isight->resources, unit);
671
672 card->private_free = isight_card_free;
673
674 strcpy(card->driver, "iSight");
675 strcpy(card->shortname, "Apple iSight");
676 snprintf(card->longname, sizeof(card->longname),
677 "Apple iSight (GUID %08x%08x) at %s, S%d",
678 fw_dev->config_rom[3], fw_dev->config_rom[4],
679 dev_name(&unit->device), 100 << fw_dev->max_speed);
680 strcpy(card->mixername, "iSight");
681
682 err = isight_create_pcm(isight);
683 if (err < 0)
684 goto error;
685
686 err = isight_create_mixer(isight);
687 if (err < 0)
688 goto error;
689
690 err = snd_card_register(card);
691 if (err < 0)
692 goto error;
693
694 dev_set_drvdata(unit_dev, isight);
695
696 return 0;
697
698err_unit:
699 fw_unit_put(isight->unit);
700 fw_device_put(isight->device);
701 mutex_destroy(&isight->mutex);
702error:
703 snd_card_free(card);
704 return err;
705}
706
707static int isight_remove(struct device *dev)
708{
709 struct isight *isight = dev_get_drvdata(dev);
710
711 snd_card_disconnect(isight->card);
712
713 mutex_lock(&isight->mutex);
714 isight_pcm_abort(isight);
715 isight_stop_streaming(isight);
716 mutex_unlock(&isight->mutex);
717
718 snd_card_free_when_closed(isight->card);
719
720 return 0;
721}
722
723static void isight_bus_reset(struct fw_unit *unit)
724{
725 struct isight *isight = dev_get_drvdata(&unit->device);
726
727 mutex_lock(&isight->mutex);
728 if (fw_iso_resources_update(&isight->resources) < 0) {
729 isight_pcm_abort(isight);
730 isight_stop_streaming(isight);
731 }
732 mutex_unlock(&isight->mutex);
733}
734
735static const struct ieee1394_device_id isight_id_table[] = {
736 {
737 .match_flags = IEEE1394_MATCH_SPECIFIER_ID |
738 IEEE1394_MATCH_VERSION,
739 .specifier_id = OUI_APPLE,
740 .version = SW_ISIGHT_AUDIO,
741 },
742 { }
743};
744MODULE_DEVICE_TABLE(ieee1394, isight_id_table);
745
746static struct fw_driver isight_driver = {
747 .driver = {
748 .owner = THIS_MODULE,
749 .name = KBUILD_MODNAME,
750 .bus = &fw_bus_type,
751 .probe = isight_probe,
752 .remove = isight_remove,
753 },
754 .update = isight_bus_reset,
755 .id_table = isight_id_table,
756};
757
758static int __init alsa_isight_init(void)
759{
760 return driver_register(&isight_driver.driver);
761}
762
763static void __exit alsa_isight_exit(void)
764{
765 driver_unregister(&isight_driver.driver);
766}
767
768module_init(alsa_isight_init);
769module_exit(alsa_isight_exit);