root/sound/firewire/isight.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isight_update_pointers
  2. isight_samples
  3. isight_pcm_abort
  4. isight_dropped_samples
  5. isight_packet
  6. isight_connect
  7. isight_open
  8. isight_close
  9. isight_hw_params
  10. reg_read
  11. reg_write
  12. isight_stop_streaming
  13. isight_hw_free
  14. isight_start_streaming
  15. isight_prepare
  16. isight_trigger
  17. isight_pointer
  18. isight_create_pcm
  19. isight_gain_info
  20. isight_gain_get
  21. isight_gain_put
  22. isight_mute_get
  23. isight_mute_put
  24. isight_create_mixer
  25. isight_card_free
  26. get_unit_base
  27. isight_probe
  28. isight_bus_reset
  29. isight_remove
  30. alsa_isight_init
  31. alsa_isight_exit

   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_alloc_vmalloc_buffer(substream,
 292                                                params_buffer_bytes(hw_params));
 293         if (err < 0)
 294                 return err;
 295 
 296         WRITE_ONCE(isight->pcm_active, true);
 297 
 298         return 0;
 299 }
 300 
 301 static int reg_read(struct isight *isight, int offset, __be32 *value)
 302 {
 303         return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
 304                                   isight->audio_base + offset, value, 4, 0);
 305 }
 306 
 307 static int reg_write(struct isight *isight, int offset, __be32 value)
 308 {
 309         return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
 310                                   isight->audio_base + offset, &value, 4, 0);
 311 }
 312 
 313 static void isight_stop_streaming(struct isight *isight)
 314 {
 315         __be32 value;
 316 
 317         if (!isight->context)
 318                 return;
 319 
 320         fw_iso_context_stop(isight->context);
 321         fw_iso_context_destroy(isight->context);
 322         isight->context = NULL;
 323         fw_iso_resources_free(&isight->resources);
 324         value = 0;
 325         snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
 326                            isight->audio_base + REG_AUDIO_ENABLE,
 327                            &value, 4, FW_QUIET);
 328 }
 329 
 330 static int isight_hw_free(struct snd_pcm_substream *substream)
 331 {
 332         struct isight *isight = substream->private_data;
 333 
 334         WRITE_ONCE(isight->pcm_active, false);
 335 
 336         mutex_lock(&isight->mutex);
 337         isight_stop_streaming(isight);
 338         mutex_unlock(&isight->mutex);
 339 
 340         return snd_pcm_lib_free_vmalloc_buffer(substream);
 341 }
 342 
 343 static int isight_start_streaming(struct isight *isight)
 344 {
 345         unsigned int i;
 346         int err;
 347 
 348         if (isight->context) {
 349                 if (isight->packet_index < 0)
 350                         isight_stop_streaming(isight);
 351                 else
 352                         return 0;
 353         }
 354 
 355         err = reg_write(isight, REG_SAMPLE_RATE, cpu_to_be32(RATE_48000));
 356         if (err < 0)
 357                 goto error;
 358 
 359         err = isight_connect(isight);
 360         if (err < 0)
 361                 goto error;
 362 
 363         err = reg_write(isight, REG_AUDIO_ENABLE, cpu_to_be32(AUDIO_ENABLE));
 364         if (err < 0)
 365                 goto err_resources;
 366 
 367         isight->context = fw_iso_context_create(isight->device->card,
 368                                                 FW_ISO_CONTEXT_RECEIVE,
 369                                                 isight->resources.channel,
 370                                                 isight->device->max_speed,
 371                                                 4, isight_packet, isight);
 372         if (IS_ERR(isight->context)) {
 373                 err = PTR_ERR(isight->context);
 374                 isight->context = NULL;
 375                 goto err_resources;
 376         }
 377 
 378         for (i = 0; i < QUEUE_LENGTH; ++i) {
 379                 err = fw_iso_context_queue(isight->context, &audio_packet,
 380                                            &isight->buffer.iso_buffer,
 381                                            isight->buffer.packets[i].offset);
 382                 if (err < 0)
 383                         goto err_context;
 384         }
 385 
 386         isight->first_packet = true;
 387         isight->packet_index = 0;
 388 
 389         err = fw_iso_context_start(isight->context, -1, 0,
 390                                    FW_ISO_CONTEXT_MATCH_ALL_TAGS/*?*/);
 391         if (err < 0)
 392                 goto err_context;
 393 
 394         return 0;
 395 
 396 err_context:
 397         fw_iso_context_destroy(isight->context);
 398         isight->context = NULL;
 399 err_resources:
 400         fw_iso_resources_free(&isight->resources);
 401         reg_write(isight, REG_AUDIO_ENABLE, 0);
 402 error:
 403         return err;
 404 }
 405 
 406 static int isight_prepare(struct snd_pcm_substream *substream)
 407 {
 408         struct isight *isight = substream->private_data;
 409         int err;
 410 
 411         isight->buffer_pointer = 0;
 412         isight->period_counter = 0;
 413 
 414         mutex_lock(&isight->mutex);
 415         err = isight_start_streaming(isight);
 416         mutex_unlock(&isight->mutex);
 417 
 418         return err;
 419 }
 420 
 421 static int isight_trigger(struct snd_pcm_substream *substream, int cmd)
 422 {
 423         struct isight *isight = substream->private_data;
 424 
 425         switch (cmd) {
 426         case SNDRV_PCM_TRIGGER_START:
 427                 WRITE_ONCE(isight->pcm_running, true);
 428                 break;
 429         case SNDRV_PCM_TRIGGER_STOP:
 430                 WRITE_ONCE(isight->pcm_running, false);
 431                 break;
 432         default:
 433                 return -EINVAL;
 434         }
 435         return 0;
 436 }
 437 
 438 static snd_pcm_uframes_t isight_pointer(struct snd_pcm_substream *substream)
 439 {
 440         struct isight *isight = substream->private_data;
 441 
 442         return READ_ONCE(isight->buffer_pointer);
 443 }
 444 
 445 static int isight_create_pcm(struct isight *isight)
 446 {
 447         static const struct snd_pcm_ops ops = {
 448                 .open      = isight_open,
 449                 .close     = isight_close,
 450                 .ioctl     = snd_pcm_lib_ioctl,
 451                 .hw_params = isight_hw_params,
 452                 .hw_free   = isight_hw_free,
 453                 .prepare   = isight_prepare,
 454                 .trigger   = isight_trigger,
 455                 .pointer   = isight_pointer,
 456                 .page      = snd_pcm_lib_get_vmalloc_page,
 457         };
 458         struct snd_pcm *pcm;
 459         int err;
 460 
 461         err = snd_pcm_new(isight->card, "iSight", 0, 0, 1, &pcm);
 462         if (err < 0)
 463                 return err;
 464         pcm->private_data = isight;
 465         strcpy(pcm->name, "iSight");
 466         isight->pcm = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
 467         isight->pcm->ops = &ops;
 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);

/* [<][>][^][v][top][bottom][index][help] */