~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to sound/firewire/isight.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

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