linux/sound/sh/aica.c
<<
>>
Prefs
   1/*
   2* This code is licenced under 
   3* the General Public Licence
   4* version 2
   5*
   6* Copyright Adrian McMenamin 2005, 2006, 2007
   7* <adrian@mcmen.demon.co.uk>
   8* Requires firmware (BSD licenced) available from:
   9* http://linuxdc.cvs.sourceforge.net/linuxdc/linux-sh-dc/sound/oss/aica/firmware/
  10* or the maintainer
  11*
  12* This program is free software; you can redistribute it and/or modify
  13* it under the terms of version 2 of the GNU General Public License as published by
  14* the Free Software Foundation.
  15*
  16* This program is distributed in the hope that it will be useful,
  17* but WITHOUT ANY WARRANTY; without even the implied warranty of
  18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19* GNU General Public License for more details.
  20*
  21* You should have received a copy of the GNU General Public License
  22* along with this program; if not, write to the Free Software
  23* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  24*
  25*/
  26
  27#include <linux/init.h>
  28#include <linux/jiffies.h>
  29#include <linux/slab.h>
  30#include <linux/time.h>
  31#include <linux/wait.h>
  32#include <linux/module.h>
  33#include <linux/platform_device.h>
  34#include <linux/firmware.h>
  35#include <linux/timer.h>
  36#include <linux/delay.h>
  37#include <linux/workqueue.h>
  38#include <sound/core.h>
  39#include <sound/control.h>
  40#include <sound/pcm.h>
  41#include <sound/initval.h>
  42#include <sound/info.h>
  43#include <asm/io.h>
  44#include <asm/dma.h>
  45#include <mach/sysasic.h>
  46#include "aica.h"
  47
  48MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
  49MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
  50MODULE_LICENSE("GPL");
  51MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}");
  52MODULE_FIRMWARE("aica_firmware.bin");
  53
  54/* module parameters */
  55#define CARD_NAME "AICA"
  56static int index = -1;
  57static char *id;
  58static bool enable = 1;
  59module_param(index, int, 0444);
  60MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
  61module_param(id, charp, 0444);
  62MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
  63module_param(enable, bool, 0644);
  64MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
  65
  66/* Use workqueue */
  67static struct workqueue_struct *aica_queue;
  68
  69/* Simple platform device */
  70static struct platform_device *pd;
  71static struct resource aica_memory_space[2] = {
  72        {
  73         .name = "AICA ARM CONTROL",
  74         .start = ARM_RESET_REGISTER,
  75         .flags = IORESOURCE_MEM,
  76         .end = ARM_RESET_REGISTER + 3,
  77         },
  78        {
  79         .name = "AICA Sound RAM",
  80         .start = SPU_MEMORY_BASE,
  81         .flags = IORESOURCE_MEM,
  82         .end = SPU_MEMORY_BASE + 0x200000 - 1,
  83         },
  84};
  85
  86/* SPU specific functions */
  87/* spu_write_wait - wait for G2-SH FIFO to clear */
  88static void spu_write_wait(void)
  89{
  90        int time_count;
  91        time_count = 0;
  92        while (1) {
  93                if (!(readl(G2_FIFO) & 0x11))
  94                        break;
  95                /* To ensure hardware failure doesn't wedge kernel */
  96                time_count++;
  97                if (time_count > 0x10000) {
  98                        snd_printk
  99                            ("WARNING: G2 FIFO appears to be blocked.\n");
 100                        break;
 101                }
 102        }
 103}
 104
 105/* spu_memset - write to memory in SPU address space */
 106static void spu_memset(u32 toi, u32 what, int length)
 107{
 108        int i;
 109        unsigned long flags;
 110        if (snd_BUG_ON(length % 4))
 111                return;
 112        for (i = 0; i < length; i++) {
 113                if (!(i % 8))
 114                        spu_write_wait();
 115                local_irq_save(flags);
 116                writel(what, toi + SPU_MEMORY_BASE);
 117                local_irq_restore(flags);
 118                toi++;
 119        }
 120}
 121
 122/* spu_memload - write to SPU address space */
 123static void spu_memload(u32 toi, void *from, int length)
 124{
 125        unsigned long flags;
 126        u32 *froml = from;
 127        u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
 128        int i;
 129        u32 val;
 130        length = DIV_ROUND_UP(length, 4);
 131        spu_write_wait();
 132        for (i = 0; i < length; i++) {
 133                if (!(i % 8))
 134                        spu_write_wait();
 135                val = *froml;
 136                local_irq_save(flags);
 137                writel(val, to);
 138                local_irq_restore(flags);
 139                froml++;
 140                to++;
 141        }
 142}
 143
 144/* spu_disable - set spu registers to stop sound output */
 145static void spu_disable(void)
 146{
 147        int i;
 148        unsigned long flags;
 149        u32 regval;
 150        spu_write_wait();
 151        regval = readl(ARM_RESET_REGISTER);
 152        regval |= 1;
 153        spu_write_wait();
 154        local_irq_save(flags);
 155        writel(regval, ARM_RESET_REGISTER);
 156        local_irq_restore(flags);
 157        for (i = 0; i < 64; i++) {
 158                spu_write_wait();
 159                regval = readl(SPU_REGISTER_BASE + (i * 0x80));
 160                regval = (regval & ~0x4000) | 0x8000;
 161                spu_write_wait();
 162                local_irq_save(flags);
 163                writel(regval, SPU_REGISTER_BASE + (i * 0x80));
 164                local_irq_restore(flags);
 165        }
 166}
 167
 168/* spu_enable - set spu registers to enable sound output */
 169static void spu_enable(void)
 170{
 171        unsigned long flags;
 172        u32 regval = readl(ARM_RESET_REGISTER);
 173        regval &= ~1;
 174        spu_write_wait();
 175        local_irq_save(flags);
 176        writel(regval, ARM_RESET_REGISTER);
 177        local_irq_restore(flags);
 178}
 179
 180/* 
 181 * Halt the sound processor, clear the memory,
 182 * load some default ARM7 code, and then restart ARM7
 183*/
 184static void spu_reset(void)
 185{
 186        unsigned long flags;
 187        spu_disable();
 188        spu_memset(0, 0, 0x200000 / 4);
 189        /* Put ARM7 in endless loop */
 190        local_irq_save(flags);
 191        __raw_writel(0xea000002, SPU_MEMORY_BASE);
 192        local_irq_restore(flags);
 193        spu_enable();
 194}
 195
 196/* aica_chn_start - write to spu to start playback */
 197static void aica_chn_start(void)
 198{
 199        unsigned long flags;
 200        spu_write_wait();
 201        local_irq_save(flags);
 202        writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
 203        local_irq_restore(flags);
 204}
 205
 206/* aica_chn_halt - write to spu to halt playback */
 207static void aica_chn_halt(void)
 208{
 209        unsigned long flags;
 210        spu_write_wait();
 211        local_irq_save(flags);
 212        writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
 213        local_irq_restore(flags);
 214}
 215
 216/* ALSA code below */
 217static struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
 218        .info = (SNDRV_PCM_INFO_NONINTERLEAVED),
 219        .formats =
 220            (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
 221             SNDRV_PCM_FMTBIT_IMA_ADPCM),
 222        .rates = SNDRV_PCM_RATE_8000_48000,
 223        .rate_min = 8000,
 224        .rate_max = 48000,
 225        .channels_min = 1,
 226        .channels_max = 2,
 227        .buffer_bytes_max = AICA_BUFFER_SIZE,
 228        .period_bytes_min = AICA_PERIOD_SIZE,
 229        .period_bytes_max = AICA_PERIOD_SIZE,
 230        .periods_min = AICA_PERIOD_NUMBER,
 231        .periods_max = AICA_PERIOD_NUMBER,
 232};
 233
 234static int aica_dma_transfer(int channels, int buffer_size,
 235                             struct snd_pcm_substream *substream)
 236{
 237        int q, err, period_offset;
 238        struct snd_card_aica *dreamcastcard;
 239        struct snd_pcm_runtime *runtime;
 240        unsigned long flags;
 241        err = 0;
 242        dreamcastcard = substream->pcm->private_data;
 243        period_offset = dreamcastcard->clicks;
 244        period_offset %= (AICA_PERIOD_NUMBER / channels);
 245        runtime = substream->runtime;
 246        for (q = 0; q < channels; q++) {
 247                local_irq_save(flags);
 248                err = dma_xfer(AICA_DMA_CHANNEL,
 249                               (unsigned long) (runtime->dma_area +
 250                                                (AICA_BUFFER_SIZE * q) /
 251                                                channels +
 252                                                AICA_PERIOD_SIZE *
 253                                                period_offset),
 254                               AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
 255                               AICA_PERIOD_SIZE * period_offset,
 256                               buffer_size / channels, AICA_DMA_MODE);
 257                if (unlikely(err < 0)) {
 258                        local_irq_restore(flags);
 259                        break;
 260                }
 261                dma_wait_for_completion(AICA_DMA_CHANNEL);
 262                local_irq_restore(flags);
 263        }
 264        return err;
 265}
 266
 267static void startup_aica(struct snd_card_aica *dreamcastcard)
 268{
 269        spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
 270                    dreamcastcard->channel, sizeof(struct aica_channel));
 271        aica_chn_start();
 272}
 273
 274static void run_spu_dma(struct work_struct *work)
 275{
 276        int buffer_size;
 277        struct snd_pcm_runtime *runtime;
 278        struct snd_card_aica *dreamcastcard;
 279        dreamcastcard =
 280            container_of(work, struct snd_card_aica, spu_dma_work);
 281        runtime = dreamcastcard->substream->runtime;
 282        if (unlikely(dreamcastcard->dma_check == 0)) {
 283                buffer_size =
 284                    frames_to_bytes(runtime, runtime->buffer_size);
 285                if (runtime->channels > 1)
 286                        dreamcastcard->channel->flags |= 0x01;
 287                aica_dma_transfer(runtime->channels, buffer_size,
 288                                  dreamcastcard->substream);
 289                startup_aica(dreamcastcard);
 290                dreamcastcard->clicks =
 291                    buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
 292                return;
 293        } else {
 294                aica_dma_transfer(runtime->channels,
 295                                  AICA_PERIOD_SIZE * runtime->channels,
 296                                  dreamcastcard->substream);
 297                snd_pcm_period_elapsed(dreamcastcard->substream);
 298                dreamcastcard->clicks++;
 299                if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
 300                        dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
 301                mod_timer(&dreamcastcard->timer, jiffies + 1);
 302        }
 303}
 304
 305static void aica_period_elapsed(unsigned long timer_var)
 306{
 307        /*timer function - so cannot sleep */
 308        int play_period;
 309        struct snd_pcm_runtime *runtime;
 310        struct snd_pcm_substream *substream;
 311        struct snd_card_aica *dreamcastcard;
 312        substream = (struct snd_pcm_substream *) timer_var;
 313        runtime = substream->runtime;
 314        dreamcastcard = substream->pcm->private_data;
 315        /* Have we played out an additional period? */
 316        play_period =
 317            frames_to_bytes(runtime,
 318                            readl
 319                            (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
 320            AICA_PERIOD_SIZE;
 321        if (play_period == dreamcastcard->current_period) {
 322                /* reschedule the timer */
 323                mod_timer(&(dreamcastcard->timer), jiffies + 1);
 324                return;
 325        }
 326        if (runtime->channels > 1)
 327                dreamcastcard->current_period = play_period;
 328        if (unlikely(dreamcastcard->dma_check == 0))
 329                dreamcastcard->dma_check = 1;
 330        queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
 331}
 332
 333static void spu_begin_dma(struct snd_pcm_substream *substream)
 334{
 335        struct snd_card_aica *dreamcastcard;
 336        struct snd_pcm_runtime *runtime;
 337        runtime = substream->runtime;
 338        dreamcastcard = substream->pcm->private_data;
 339        /*get the queue to do the work */
 340        queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
 341        /* Timer may already be running */
 342        if (unlikely(dreamcastcard->timer.data)) {
 343                mod_timer(&dreamcastcard->timer, jiffies + 4);
 344                return;
 345        }
 346        init_timer(&(dreamcastcard->timer));
 347        dreamcastcard->timer.data = (unsigned long) substream;
 348        dreamcastcard->timer.function = aica_period_elapsed;
 349        dreamcastcard->timer.expires = jiffies + 4;
 350        add_timer(&(dreamcastcard->timer));
 351}
 352
 353static int snd_aicapcm_pcm_open(struct snd_pcm_substream
 354                                *substream)
 355{
 356        struct snd_pcm_runtime *runtime;
 357        struct aica_channel *channel;
 358        struct snd_card_aica *dreamcastcard;
 359        if (!enable)
 360                return -ENOENT;
 361        dreamcastcard = substream->pcm->private_data;
 362        channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
 363        if (!channel)
 364                return -ENOMEM;
 365        /* set defaults for channel */
 366        channel->sfmt = SM_8BIT;
 367        channel->cmd = AICA_CMD_START;
 368        channel->vol = dreamcastcard->master_volume;
 369        channel->pan = 0x80;
 370        channel->pos = 0;
 371        channel->flags = 0;     /* default to mono */
 372        dreamcastcard->channel = channel;
 373        runtime = substream->runtime;
 374        runtime->hw = snd_pcm_aica_playback_hw;
 375        spu_enable();
 376        dreamcastcard->clicks = 0;
 377        dreamcastcard->current_period = 0;
 378        dreamcastcard->dma_check = 0;
 379        return 0;
 380}
 381
 382static int snd_aicapcm_pcm_close(struct snd_pcm_substream
 383                                 *substream)
 384{
 385        struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
 386        flush_workqueue(aica_queue);
 387        if (dreamcastcard->timer.data)
 388                del_timer(&dreamcastcard->timer);
 389        kfree(dreamcastcard->channel);
 390        spu_disable();
 391        return 0;
 392}
 393
 394static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream
 395                                   *substream)
 396{
 397        /* Free the DMA buffer */
 398        return snd_pcm_lib_free_pages(substream);
 399}
 400
 401static int snd_aicapcm_pcm_hw_params(struct snd_pcm_substream
 402                                     *substream, struct snd_pcm_hw_params
 403                                     *hw_params)
 404{
 405        /* Allocate a DMA buffer using ALSA built-ins */
 406        return
 407            snd_pcm_lib_malloc_pages(substream,
 408                                     params_buffer_bytes(hw_params));
 409}
 410
 411static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
 412                                   *substream)
 413{
 414        struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
 415        if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
 416                dreamcastcard->channel->sfmt = SM_16BIT;
 417        dreamcastcard->channel->freq = substream->runtime->rate;
 418        dreamcastcard->substream = substream;
 419        return 0;
 420}
 421
 422static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
 423                                   *substream, int cmd)
 424{
 425        switch (cmd) {
 426        case SNDRV_PCM_TRIGGER_START:
 427                spu_begin_dma(substream);
 428                break;
 429        case SNDRV_PCM_TRIGGER_STOP:
 430                aica_chn_halt();
 431                break;
 432        default:
 433                return -EINVAL;
 434        }
 435        return 0;
 436}
 437
 438static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
 439                                             *substream)
 440{
 441        return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
 442}
 443
 444static struct snd_pcm_ops snd_aicapcm_playback_ops = {
 445        .open = snd_aicapcm_pcm_open,
 446        .close = snd_aicapcm_pcm_close,
 447        .ioctl = snd_pcm_lib_ioctl,
 448        .hw_params = snd_aicapcm_pcm_hw_params,
 449        .hw_free = snd_aicapcm_pcm_hw_free,
 450        .prepare = snd_aicapcm_pcm_prepare,
 451        .trigger = snd_aicapcm_pcm_trigger,
 452        .pointer = snd_aicapcm_pcm_pointer,
 453};
 454
 455/* TO DO: set up to handle more than one pcm instance */
 456static int __init snd_aicapcmchip(struct snd_card_aica
 457                                  *dreamcastcard, int pcm_index)
 458{
 459        struct snd_pcm *pcm;
 460        int err;
 461        /* AICA has no capture ability */
 462        err =
 463            snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,
 464                        &pcm);
 465        if (unlikely(err < 0))
 466                return err;
 467        pcm->private_data = dreamcastcard;
 468        strcpy(pcm->name, "AICA PCM");
 469        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 470                        &snd_aicapcm_playback_ops);
 471        /* Allocate the DMA buffers */
 472        err =
 473            snd_pcm_lib_preallocate_pages_for_all(pcm,
 474                                                  SNDRV_DMA_TYPE_CONTINUOUS,
 475                                                  snd_dma_continuous_data
 476                                                  (GFP_KERNEL),
 477                                                  AICA_BUFFER_SIZE,
 478                                                  AICA_BUFFER_SIZE);
 479        return err;
 480}
 481
 482/* Mixer controls */
 483#define aica_pcmswitch_info             snd_ctl_boolean_mono_info
 484
 485static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
 486                              struct snd_ctl_elem_value *ucontrol)
 487{
 488        ucontrol->value.integer.value[0] = 1;   /* TO DO: Fix me */
 489        return 0;
 490}
 491
 492static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
 493                              struct snd_ctl_elem_value *ucontrol)
 494{
 495        if (ucontrol->value.integer.value[0] == 1)
 496                return 0;       /* TO DO: Fix me */
 497        else
 498                aica_chn_halt();
 499        return 0;
 500}
 501
 502static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
 503                               struct snd_ctl_elem_info *uinfo)
 504{
 505        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 506        uinfo->count = 1;
 507        uinfo->value.integer.min = 0;
 508        uinfo->value.integer.max = 0xFF;
 509        return 0;
 510}
 511
 512static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
 513                              struct snd_ctl_elem_value *ucontrol)
 514{
 515        struct snd_card_aica *dreamcastcard;
 516        dreamcastcard = kcontrol->private_data;
 517        if (unlikely(!dreamcastcard->channel))
 518                return -ETXTBSY;        /* we've not yet been set up */
 519        ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
 520        return 0;
 521}
 522
 523static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
 524                              struct snd_ctl_elem_value *ucontrol)
 525{
 526        struct snd_card_aica *dreamcastcard;
 527        unsigned int vol;
 528        dreamcastcard = kcontrol->private_data;
 529        if (unlikely(!dreamcastcard->channel))
 530                return -ETXTBSY;
 531        vol = ucontrol->value.integer.value[0];
 532        if (vol > 0xff)
 533                return -EINVAL;
 534        if (unlikely(dreamcastcard->channel->vol == vol))
 535                return 0;
 536        dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
 537        dreamcastcard->master_volume = ucontrol->value.integer.value[0];
 538        spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
 539                    dreamcastcard->channel, sizeof(struct aica_channel));
 540        return 1;
 541}
 542
 543static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = {
 544        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 545        .name = "PCM Playback Switch",
 546        .index = 0,
 547        .info = aica_pcmswitch_info,
 548        .get = aica_pcmswitch_get,
 549        .put = aica_pcmswitch_put
 550};
 551
 552static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = {
 553        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 554        .name = "PCM Playback Volume",
 555        .index = 0,
 556        .info = aica_pcmvolume_info,
 557        .get = aica_pcmvolume_get,
 558        .put = aica_pcmvolume_put
 559};
 560
 561static int load_aica_firmware(void)
 562{
 563        int err;
 564        const struct firmware *fw_entry;
 565        spu_reset();
 566        err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
 567        if (unlikely(err))
 568                return err;
 569        /* write firmware into memory */
 570        spu_disable();
 571        spu_memload(0, fw_entry->data, fw_entry->size);
 572        spu_enable();
 573        release_firmware(fw_entry);
 574        return err;
 575}
 576
 577static int __devinit add_aicamixer_controls(struct snd_card_aica
 578                                            *dreamcastcard)
 579{
 580        int err;
 581        err = snd_ctl_add
 582            (dreamcastcard->card,
 583             snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
 584        if (unlikely(err < 0))
 585                return err;
 586        err = snd_ctl_add
 587            (dreamcastcard->card,
 588             snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
 589        if (unlikely(err < 0))
 590                return err;
 591        return 0;
 592}
 593
 594static int __devexit snd_aica_remove(struct platform_device *devptr)
 595{
 596        struct snd_card_aica *dreamcastcard;
 597        dreamcastcard = platform_get_drvdata(devptr);
 598        if (unlikely(!dreamcastcard))
 599                return -ENODEV;
 600        snd_card_free(dreamcastcard->card);
 601        kfree(dreamcastcard);
 602        platform_set_drvdata(devptr, NULL);
 603        return 0;
 604}
 605
 606static int __devinit snd_aica_probe(struct platform_device *devptr)
 607{
 608        int err;
 609        struct snd_card_aica *dreamcastcard;
 610        dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
 611        if (unlikely(!dreamcastcard))
 612                return -ENOMEM;
 613        err = snd_card_create(index, SND_AICA_DRIVER, THIS_MODULE, 0,
 614                              &dreamcastcard->card);
 615        if (unlikely(err < 0)) {
 616                kfree(dreamcastcard);
 617                return err;
 618        }
 619        strcpy(dreamcastcard->card->driver, "snd_aica");
 620        strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
 621        strcpy(dreamcastcard->card->longname,
 622               "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
 623        /* Prepare to use the queue */
 624        INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
 625        /* Load the PCM 'chip' */
 626        err = snd_aicapcmchip(dreamcastcard, 0);
 627        if (unlikely(err < 0))
 628                goto freedreamcast;
 629        snd_card_set_dev(dreamcastcard->card, &devptr->dev);
 630        dreamcastcard->timer.data = 0;
 631        dreamcastcard->channel = NULL;
 632        /* Add basic controls */
 633        err = add_aicamixer_controls(dreamcastcard);
 634        if (unlikely(err < 0))
 635                goto freedreamcast;
 636        /* Register the card with ALSA subsystem */
 637        err = snd_card_register(dreamcastcard->card);
 638        if (unlikely(err < 0))
 639                goto freedreamcast;
 640        platform_set_drvdata(devptr, dreamcastcard);
 641        aica_queue = create_workqueue(CARD_NAME);
 642        if (unlikely(!aica_queue))
 643                goto freedreamcast;
 644        snd_printk
 645            ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
 646        return 0;
 647      freedreamcast:
 648        snd_card_free(dreamcastcard->card);
 649        kfree(dreamcastcard);
 650        return err;
 651}
 652
 653static struct platform_driver snd_aica_driver = {
 654        .probe = snd_aica_probe,
 655        .remove = __devexit_p(snd_aica_remove),
 656        .driver = {
 657                .name = SND_AICA_DRIVER,
 658                .owner  = THIS_MODULE,
 659        },
 660};
 661
 662static int __init aica_init(void)
 663{
 664        int err;
 665        err = platform_driver_register(&snd_aica_driver);
 666        if (unlikely(err < 0))
 667                return err;
 668        pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
 669                                             aica_memory_space, 2);
 670        if (IS_ERR(pd)) {
 671                platform_driver_unregister(&snd_aica_driver);
 672                return PTR_ERR(pd);
 673        }
 674        /* Load the firmware */
 675        return load_aica_firmware();
 676}
 677
 678static void __exit aica_exit(void)
 679{
 680        /* Destroy the aica kernel thread            *
 681         * being extra cautious to check if it exists*/
 682        if (likely(aica_queue))
 683                destroy_workqueue(aica_queue);
 684        platform_device_unregister(pd);
 685        platform_driver_unregister(&snd_aica_driver);
 686        /* Kill any sound still playing and reset ARM7 to safe state */
 687        spu_reset();
 688}
 689
 690module_init(aica_init);
 691module_exit(aica_exit);
 692
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.