linux/sound/oss/vidc.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/sound/vidc.c
   3 *
   4 *  Copyright (C) 1997-2000 by Russell King <rmk@arm.linux.org.uk>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 *  VIDC20 audio driver.
  11 *
  12 * The VIDC20 sound hardware consists of the VIDC20 itself, a DAC and a DMA
  13 * engine.  The DMA transfers fixed-format (16-bit little-endian linear)
  14 * samples to the VIDC20, which then transfers this data serially to the
  15 * DACs.  The samplerate is controlled by the VIDC.
  16 *
  17 * We currently support a mixer device, but it is currently non-functional.
  18 */
  19
  20#include <linux/gfp.h>
  21#include <linux/init.h>
  22#include <linux/module.h>
  23#include <linux/kernel.h>
  24#include <linux/interrupt.h>
  25
  26#include <mach/hardware.h>
  27#include <asm/dma.h>
  28#include <asm/io.h>
  29#include <asm/hardware/iomd.h>
  30#include <asm/irq.h>
  31#include <asm/system.h>
  32
  33#include "sound_config.h"
  34#include "vidc.h"
  35
  36#ifndef _SIOC_TYPE
  37#define _SIOC_TYPE(x)   _IOC_TYPE(x)
  38#endif
  39#ifndef _SIOC_NR
  40#define _SIOC_NR(x)     _IOC_NR(x)
  41#endif
  42
  43#define VIDC_SOUND_CLOCK        (250000)
  44#define VIDC_SOUND_CLOCK_EXT    (176400)
  45
  46/*
  47 * When using SERIAL SOUND mode (external DAC), the number of physical
  48 * channels is fixed at 2.
  49 */
  50static int              vidc_busy;
  51static int              vidc_adev;
  52static int              vidc_audio_rate;
  53static char             vidc_audio_format;
  54static char             vidc_audio_channels;
  55
  56static unsigned char    vidc_level_l[SOUND_MIXER_NRDEVICES] = {
  57        85,             /* master       */
  58        50,             /* bass         */
  59        50,             /* treble       */
  60        0,              /* synth        */
  61        75,             /* pcm          */
  62        0,              /* speaker      */
  63        100,            /* ext line     */
  64        0,              /* mic          */
  65        100,            /* CD           */
  66        0,
  67};
  68
  69static unsigned char    vidc_level_r[SOUND_MIXER_NRDEVICES] = {
  70        85,             /* master       */
  71        50,             /* bass         */
  72        50,             /* treble       */
  73        0,              /* synth        */
  74        75,             /* pcm          */
  75        0,              /* speaker      */
  76        100,            /* ext line     */
  77        0,              /* mic          */
  78        100,            /* CD           */
  79        0,
  80};
  81
  82static unsigned int     vidc_audio_volume_l;    /* left PCM vol, 0 - 65536 */
  83static unsigned int     vidc_audio_volume_r;    /* right PCM vol, 0 - 65536 */
  84
  85extern void     vidc_update_filler(int bits, int channels);
  86extern int      softoss_dev;
  87
  88static void
  89vidc_mixer_set(int mdev, unsigned int level)
  90{
  91        unsigned int lev_l = level & 0x007f;
  92        unsigned int lev_r = (level & 0x7f00) >> 8;
  93        unsigned int mlev_l, mlev_r;
  94
  95        if (lev_l > 100)
  96                lev_l = 100;
  97        if (lev_r > 100)
  98                lev_r = 100;
  99
 100#define SCALE(lev,master)       ((lev) * (master) * 65536 / 10000)
 101
 102        mlev_l = vidc_level_l[SOUND_MIXER_VOLUME];
 103        mlev_r = vidc_level_r[SOUND_MIXER_VOLUME];
 104
 105        switch (mdev) {
 106        case SOUND_MIXER_VOLUME:
 107        case SOUND_MIXER_PCM:
 108                vidc_level_l[mdev] = lev_l;
 109                vidc_level_r[mdev] = lev_r;
 110
 111                vidc_audio_volume_l = SCALE(lev_l, mlev_l);
 112                vidc_audio_volume_r = SCALE(lev_r, mlev_r);
 113/*printk("VIDC: PCM vol %05X %05X\n", vidc_audio_volume_l, vidc_audio_volume_r);*/
 114                break;
 115        }
 116#undef SCALE
 117}
 118
 119static int vidc_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
 120{
 121        unsigned int val;
 122        unsigned int mdev;
 123
 124        if (_SIOC_TYPE(cmd) != 'M')
 125                return -EINVAL;
 126
 127        mdev = _SIOC_NR(cmd);
 128
 129        if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
 130                if (get_user(val, (unsigned int __user *)arg))
 131                        return -EFAULT;
 132
 133                if (mdev < SOUND_MIXER_NRDEVICES)
 134                        vidc_mixer_set(mdev, val);
 135                else
 136                        return -EINVAL;
 137        }
 138
 139        /*
 140         * Return parameters
 141         */
 142        switch (mdev) {
 143        case SOUND_MIXER_RECSRC:
 144                val = 0;
 145                break;
 146
 147        case SOUND_MIXER_DEVMASK:
 148                val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
 149                break;
 150
 151        case SOUND_MIXER_STEREODEVS:
 152                val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
 153                break;
 154
 155        case SOUND_MIXER_RECMASK:
 156                val = 0;
 157                break;
 158
 159        case SOUND_MIXER_CAPS:
 160                val = 0;
 161                break;
 162
 163        default:
 164                if (mdev < SOUND_MIXER_NRDEVICES)
 165                        val = vidc_level_l[mdev] | vidc_level_r[mdev] << 8;
 166                else
 167                        return -EINVAL;
 168        }
 169
 170        return put_user(val, (unsigned int __user *)arg) ? -EFAULT : 0;
 171}
 172
 173static unsigned int vidc_audio_set_format(int dev, unsigned int fmt)
 174{
 175        switch (fmt) {
 176        default:
 177                fmt = AFMT_S16_LE;
 178        case AFMT_U8:
 179        case AFMT_S8:
 180        case AFMT_S16_LE:
 181                vidc_audio_format = fmt;
 182                vidc_update_filler(vidc_audio_format, vidc_audio_channels);
 183        case AFMT_QUERY:
 184                break;
 185        }
 186        return vidc_audio_format;
 187}
 188
 189#define my_abs(i) ((i)<0 ? -(i) : (i))
 190
 191static int vidc_audio_set_speed(int dev, int rate)
 192{
 193        if (rate) {
 194                unsigned int hwctrl, hwrate, hwrate_ext, rate_int, rate_ext;
 195                unsigned int diff_int, diff_ext;
 196                unsigned int newsize, new2size;
 197
 198                hwctrl = 0x00000003;
 199
 200                /* Using internal clock */
 201                hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1;
 202                if (hwrate < 3)
 203                        hwrate = 3;
 204                if (hwrate > 255)
 205                        hwrate = 255;
 206
 207                /* Using exernal clock */
 208                hwrate_ext = (((VIDC_SOUND_CLOCK_EXT * 2) / rate) + 1) >> 1;
 209                if (hwrate_ext < 3)
 210                        hwrate_ext = 3;
 211                if (hwrate_ext > 255)
 212                        hwrate_ext = 255;
 213
 214                rate_int = VIDC_SOUND_CLOCK / hwrate;
 215                rate_ext = VIDC_SOUND_CLOCK_EXT / hwrate_ext;
 216
 217                /* Chose between external and internal clock */
 218                diff_int = my_abs(rate_ext-rate);
 219                diff_ext = my_abs(rate_int-rate);
 220                if (diff_ext < diff_int) {
 221                        /*printk("VIDC: external %d %d %d\n", rate, rate_ext, hwrate_ext);*/
 222                        hwrate=hwrate_ext;
 223                        hwctrl=0x00000002;
 224                        /* Allow roughly 0.4% tolerance */
 225                        if (diff_ext > (rate/256))
 226                                rate=rate_ext;
 227                } else {
 228                        /*printk("VIDC: internal %d %d %d\n", rate, rate_int, hwrate);*/
 229                        hwctrl=0x00000003;
 230                        /* Allow roughly 0.4% tolerance */
 231                        if (diff_int > (rate/256))
 232                                rate=rate_int;
 233                }
 234
 235                vidc_writel(0xb0000000 | (hwrate - 2));
 236                vidc_writel(0xb1000000 | hwctrl);
 237
 238                newsize = (10000 / hwrate) & ~3;
 239                if (newsize < 208)
 240                        newsize = 208;
 241                if (newsize > 4096)
 242                        newsize = 4096;
 243                for (new2size = 128; new2size < newsize; new2size <<= 1);
 244                if (new2size - newsize > newsize - (new2size >> 1))
 245                        new2size >>= 1;
 246                if (new2size > 4096) {
 247                        printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4K\n",
 248                                newsize, new2size);
 249                        new2size = 4096;
 250                }
 251                /*printk("VIDC: dma size %d\n", new2size);*/
 252                dma_bufsize = new2size;
 253                vidc_audio_rate = rate;
 254        }
 255        return vidc_audio_rate;
 256}
 257
 258static short vidc_audio_set_channels(int dev, short channels)
 259{
 260        switch (channels) {
 261        default:
 262                channels = 2;
 263        case 1:
 264        case 2:
 265                vidc_audio_channels = channels;
 266                vidc_update_filler(vidc_audio_format, vidc_audio_channels);
 267        case 0:
 268                break;
 269        }
 270        return vidc_audio_channels;
 271}
 272
 273/*
 274 * Open the device
 275 */
 276static int vidc_audio_open(int dev, int mode)
 277{
 278        /* This audio device does not have recording capability */
 279        if (mode == OPEN_READ)
 280                return -EPERM;
 281
 282        if (vidc_busy)
 283                return -EBUSY;
 284
 285        vidc_busy = 1;
 286        return 0;
 287}
 288
 289/*
 290 * Close the device
 291 */
 292static void vidc_audio_close(int dev)
 293{
 294        vidc_busy = 0;
 295}
 296
 297/*
 298 * Output a block via DMA to sound device.
 299 *
 300 * We just set the DMA start and count; the DMA interrupt routine
 301 * will take care of formatting the samples (via the appropriate
 302 * vidc_filler routine), and flag via vidc_audio_dma_interrupt when
 303 * more data is required.
 304 */
 305static void
 306vidc_audio_output_block(int dev, unsigned long buf, int total_count, int one)
 307{
 308        struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 309        unsigned long flags;
 310
 311        local_irq_save(flags);
 312        dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf;
 313        dma_count = total_count;
 314        local_irq_restore(flags);
 315}
 316
 317static void
 318vidc_audio_start_input(int dev, unsigned long buf, int count, int intrflag)
 319{
 320}
 321
 322static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount)
 323{
 324        return -EINVAL;
 325}
 326
 327static irqreturn_t vidc_audio_dma_interrupt(void)
 328{
 329        DMAbuf_outputintr(vidc_adev, 1);
 330        return IRQ_HANDLED;
 331}
 332
 333/*
 334 * Prepare for outputting samples.
 335 *
 336 * Each buffer that will be passed will be `bsize' bytes long,
 337 * with a total of `bcount' buffers.
 338 */
 339static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount)
 340{
 341        struct audio_operations *adev = audio_devs[dev];
 342
 343        dma_interrupt = NULL;
 344        adev->dmap_out->flags |= DMA_NODMA;
 345
 346        return 0;
 347}
 348
 349/*
 350 * Stop our current operation.
 351 */
 352static void vidc_audio_reset(int dev)
 353{
 354        dma_interrupt = NULL;
 355}
 356
 357static int vidc_audio_local_qlen(int dev)
 358{
 359        return /*dma_count !=*/ 0;
 360}
 361
 362static void vidc_audio_trigger(int dev, int enable_bits)
 363{
 364        struct audio_operations *adev = audio_devs[dev];
 365
 366        if (enable_bits & PCM_ENABLE_OUTPUT) {
 367                if (!(adev->dmap_out->flags & DMA_ACTIVE)) {
 368                        unsigned long flags;
 369
 370                        local_irq_save(flags);
 371
 372                        /* prevent recusion */
 373                        adev->dmap_out->flags |= DMA_ACTIVE;
 374
 375                        dma_interrupt = vidc_audio_dma_interrupt;
 376                        vidc_sound_dma_irq(0, NULL);
 377                        iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR);
 378
 379                        local_irq_restore(flags);
 380                }
 381        }
 382}
 383
 384static struct audio_driver vidc_audio_driver =
 385{
 386        .owner                  = THIS_MODULE,
 387        .open                   = vidc_audio_open,
 388        .close                  = vidc_audio_close,
 389        .output_block           = vidc_audio_output_block,
 390        .start_input            = vidc_audio_start_input,
 391        .prepare_for_input      = vidc_audio_prepare_for_input,
 392        .prepare_for_output     = vidc_audio_prepare_for_output,
 393        .halt_io                = vidc_audio_reset,
 394        .local_qlen             = vidc_audio_local_qlen,
 395        .trigger                = vidc_audio_trigger,
 396        .set_speed              = vidc_audio_set_speed,
 397        .set_bits               = vidc_audio_set_format,
 398        .set_channels           = vidc_audio_set_channels
 399};
 400
 401static struct mixer_operations vidc_mixer_operations = {
 402        .owner          = THIS_MODULE,
 403        .id             = "VIDC",
 404        .name           = "VIDCsound",
 405        .ioctl          = vidc_mixer_ioctl
 406};
 407
 408void vidc_update_filler(int format, int channels)
 409{
 410#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
 411
 412        switch (TYPE(format, channels)) {
 413        default:
 414        case TYPE(AFMT_U8, 1):
 415                vidc_filler = vidc_fill_1x8_u;
 416                break;
 417
 418        case TYPE(AFMT_U8, 2):
 419                vidc_filler = vidc_fill_2x8_u;
 420                break;
 421
 422        case TYPE(AFMT_S8, 1):
 423                vidc_filler = vidc_fill_1x8_s;
 424                break;
 425
 426        case TYPE(AFMT_S8, 2):
 427                vidc_filler = vidc_fill_2x8_s;
 428                break;
 429
 430        case TYPE(AFMT_S16_LE, 1):
 431                vidc_filler = vidc_fill_1x16_s;
 432                break;
 433
 434        case TYPE(AFMT_S16_LE, 2):
 435                vidc_filler = vidc_fill_2x16_s;
 436                break;
 437        }
 438}
 439
 440static void __init attach_vidc(struct address_info *hw_config)
 441{
 442        char name[32];
 443        int i, adev;
 444
 445        sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype);
 446        conf_printf(name, hw_config);
 447        memset(dma_buf, 0, sizeof(dma_buf));
 448
 449        adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name,
 450                        &vidc_audio_driver, sizeof(vidc_audio_driver),
 451                        DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE,
 452                        NULL, hw_config->dma, hw_config->dma2);
 453
 454        if (adev < 0)
 455                goto audio_failed;
 456
 457        /*
 458         * 1024 bytes => 64 buffers
 459         */
 460        audio_devs[adev]->min_fragment = 10;
 461        audio_devs[adev]->mixer_dev = num_mixers;
 462
 463        audio_devs[adev]->mixer_dev =
 464                sound_install_mixer(MIXER_DRIVER_VERSION,
 465                                name, &vidc_mixer_operations,
 466                                sizeof(vidc_mixer_operations), NULL);
 467
 468        if (audio_devs[adev]->mixer_dev < 0)
 469                goto mixer_failed;
 470
 471        for (i = 0; i < 2; i++) {
 472                dma_buf[i] = get_zeroed_page(GFP_KERNEL);
 473                if (!dma_buf[i]) {
 474                        printk(KERN_ERR "%s: can't allocate required buffers\n",
 475                                name);
 476                        goto mem_failed;
 477                }
 478                dma_pbuf[i] = virt_to_phys((void *)dma_buf[i]);
 479        }
 480
 481        if (sound_alloc_dma(hw_config->dma, hw_config->name)) {
 482                printk(KERN_ERR "%s: DMA %d is in  use\n", name, hw_config->dma);
 483                goto dma_failed;
 484        }
 485
 486        if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0,
 487                        hw_config->name, &dma_start)) {
 488                printk(KERN_ERR "%s: IRQ %d is in use\n", name, hw_config->irq);
 489                goto irq_failed;
 490        }
 491        vidc_adev = adev;
 492        vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
 493
 494        return;
 495
 496irq_failed:
 497        sound_free_dma(hw_config->dma);
 498dma_failed:
 499mem_failed:
 500        for (i = 0; i < 2; i++)
 501                free_page(dma_buf[i]);
 502        sound_unload_mixerdev(audio_devs[adev]->mixer_dev);
 503mixer_failed:
 504        sound_unload_audiodev(adev);
 505audio_failed:
 506        return;
 507}
 508
 509static int __init probe_vidc(struct address_info *hw_config)
 510{
 511        hw_config->irq          = IRQ_DMAS0;
 512        hw_config->dma          = DMA_VIRTUAL_SOUND;
 513        hw_config->dma2         = -1;
 514        hw_config->card_subtype = 16;
 515        hw_config->name         = "VIDC20";
 516        return 1;
 517}
 518
 519static void __exit unload_vidc(struct address_info *hw_config)
 520{
 521        int i, adev = vidc_adev;
 522
 523        vidc_adev = -1;
 524
 525        free_irq(hw_config->irq, &dma_start);
 526        sound_free_dma(hw_config->dma);
 527
 528        if (adev >= 0) {
 529                sound_unload_mixerdev(audio_devs[adev]->mixer_dev);
 530                sound_unload_audiodev(adev);
 531                for (i = 0; i < 2; i++)
 532                        free_page(dma_buf[i]);
 533        }
 534}
 535
 536static struct address_info cfg;
 537
 538static int __init init_vidc(void)
 539{
 540        if (probe_vidc(&cfg) == 0)
 541                return -ENODEV;
 542
 543        attach_vidc(&cfg);
 544
 545        return 0;
 546}
 547
 548static void __exit cleanup_vidc(void)
 549{
 550        unload_vidc(&cfg);
 551}
 552
 553module_init(init_vidc);
 554module_exit(cleanup_vidc);
 555
 556MODULE_AUTHOR("Russell King");
 557MODULE_DESCRIPTION("VIDC20 audio driver");
 558MODULE_LICENSE("GPL");
 559