~ubuntu-branches/ubuntu/oneiric/oss4/oneiric-proposed

« back to all changes in this revision

Viewing changes to kernel/drv/oss_ali5455/oss_ali5455.c

  • Committer: Bazaar Package Importer
  • Author(s): Stefano Rivera
  • Date: 2011-06-16 20:37:48 UTC
  • mfrom: (5.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110616203748-jbrxik6ql33z54co
Tags: 4.2-build2004-1ubuntu1
* Merge from Debian unstable.
  - Supports our current kernel (LP: #746048)
  Remaining changes:
  - debian/oss4-dkms.dkms.in: s/source/build/ in Kernel headers paths.
* ld-as-needed.patch: Re-order CC arguments to enable building with ld
  --as-needed (LP: #770972)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Purpose: Driver for the ALI 5455 (AC97) audio controller
 
3
 */
 
4
/*
 
5
 *
 
6
 * This file is part of Open Sound System.
 
7
 *
 
8
 * Copyright (C) 4Front Technologies 1996-2008.
 
9
 *
 
10
 * This this source file is released under GPL v2 license (no other versions).
 
11
 * See the COPYING file included in the main directory of this source
 
12
 * distribution for the license terms and conditions.
 
13
 *
 
14
 */
 
15
 
 
16
#include "oss_ali5455_cfg.h"
 
17
#include <oss_pci.h>
 
18
#include <ac97.h>
 
19
 
 
20
#define ALI_VENDOR_ID           0x10b9
 
21
#define ALI_DEVICE_5455         0x5455
 
22
 
 
23
#define MAX_ALI5455 1
 
24
#define MAX_PORTC 3
 
25
#define BDL_SIZE        32
 
26
 
 
27
#ifdef OSS_BIG_ENDIAN
 
28
static __inline__ unsigned int
 
29
swap32 (unsigned int x)
 
30
{
 
31
  return ((x & 0x000000ff) << 24) |
 
32
    ((x & 0x0000ff00) << 8) |
 
33
    ((x & 0x00ff0000) >> 8) | ((x & 0xff000000) >> 24);
 
34
}
 
35
 
 
36
static __inline__ unsigned short
 
37
swap16 (unsigned short x)
 
38
{
 
39
  return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
 
40
}
 
41
 
 
42
#define SWAP32(x) swap32(x)
 
43
#define SWAP16(x) swap16(x)
 
44
#else
 
45
#define SWAP32(x)       x
 
46
#define SWAP16(x)       x
 
47
#endif
 
48
 
 
49
typedef struct
 
50
{
 
51
  int open_mode;
 
52
  int speed, bits, channels;
 
53
  int audio_enabled;
 
54
  int trigger_bits;
 
55
  int audiodev;
 
56
  int port_type;
 
57
#define DF_PCM 0
 
58
#define DF_SPDIF 1
 
59
}
 
60
ALI_portc;
 
61
 
 
62
typedef struct
 
63
{
 
64
  unsigned int addr;
 
65
  unsigned short size;
 
66
  unsigned short flags;
 
67
}
 
68
bdl_t;
 
69
 
 
70
typedef struct ALI_devc
 
71
{
 
72
  oss_device_t *osdev;
 
73
  oss_native_word base;
 
74
  int irq;
 
75
  oss_mutex_t mutex;
 
76
  oss_mutex_t low_mutex;
 
77
 
 
78
  /* Mixer */
 
79
  ac97_devc ac97devc;
 
80
  int mixer_dev;
 
81
 
 
82
  /* Audio parameters */
 
83
  int open_mode;
 
84
 
 
85
  /* Buffer Descriptor List */
 
86
  char *bdlBuffer;
 
87
  bdl_t *playBDL, *recBDL, *spdifBDL;
 
88
  oss_native_word playBDL_phys, recBDL_phys, spdifBDL_phys;
 
89
  oss_dma_handle_t bdl_dma_handle;
 
90
 
 
91
  int play_currbuf, play_currfrag;
 
92
  int spdif_currbuf, spdif_currfrag;
 
93
  int rec_currbuf, rec_currfrag;
 
94
  char *chip_name;
 
95
  ALI_portc portc[MAX_PORTC];
 
96
  int play_frag_index[BDL_SIZE];
 
97
  int rec_frag_index[BDL_SIZE];
 
98
  int spdif_frag_index[BDL_SIZE];
 
99
}
 
100
ALI_devc;
 
101
 
 
102
static int
 
103
ac97_read (void *devc_, int reg)
 
104
{
 
105
  ALI_devc *devc = devc_;
 
106
  int i = 100;
 
107
  unsigned int status;
 
108
  unsigned int data = 0;
 
109
  unsigned short read_reg = 0;
 
110
  oss_native_word flags;
 
111
 
 
112
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
113
  status = INB (devc->osdev, devc->base + 0x34);
 
114
 
 
115
  /* wait for the Codec Access Semaphore bit to be set */
 
116
  while (i-- && (INL (devc->osdev, devc->base + 0x3c) & 0x80000000))
 
117
    oss_udelay (1);
 
118
 
 
119
  for (i = 0; i < 100; i++)
 
120
    {
 
121
      status = INB (devc->osdev, devc->base + 0x38);
 
122
      if (status & 0x08)
 
123
        break;
 
124
    }
 
125
  if (i == 100)
 
126
    {
 
127
      cmn_err (CE_WARN, "AC97 not ready for read\n");
 
128
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
129
      return 0;
 
130
    }
 
131
 
 
132
  OUTW (devc->osdev, reg | 0x80, devc->base + 0x22);
 
133
 
 
134
  for (i = 0; i < 100; i++)
 
135
    {
 
136
      status = INB (devc->osdev, devc->base + 0x38);
 
137
 
 
138
      if (status & 0x02)
 
139
        {
 
140
 
 
141
          data = INW (devc->osdev, devc->base + 0x24);
 
142
          read_reg = INW (devc->osdev, devc->base + 0x26);
 
143
          break;
 
144
        }
 
145
    }
 
146
 
 
147
  if (i == 100)
 
148
    {
 
149
      cmn_err (CE_WARN, "AC97 read timed out \n");
 
150
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
151
      return 0;
 
152
    }
 
153
 
 
154
  if (read_reg != reg)
 
155
    {
 
156
      cmn_err (CE_WARN, "AC97 invalid reg read %x (%x)\n", read_reg, reg);
 
157
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
158
      return 0;
 
159
    }
 
160
 
 
161
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
162
  return data;
 
163
}
 
164
 
 
165
static int
 
166
ac97_write (void *devc_, int reg, int data)
 
167
{
 
168
  ALI_devc *devc = devc_;
 
169
  int i = 100, status;
 
170
  oss_native_word flags;
 
171
 
 
172
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
173
  /* wait for the Codec Access Semaphore bit to be set */
 
174
  while (i-- && (INL (devc->osdev, devc->base + 0x3c) & 0x80000000))
 
175
    oss_udelay (1);
 
176
 
 
177
  /* wait until command port is ready for write */
 
178
  for (i = 0; i < 100; i++)
 
179
    {
 
180
      status = INB (devc->osdev, devc->base + 0x38);
 
181
      if (status & 0x01)
 
182
        break;
 
183
    }
 
184
 
 
185
  if (i == 100)
 
186
    {
 
187
      cmn_err (CE_WARN, "AC97 timed out for write\n");
 
188
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
189
      return 0;
 
190
    }
 
191
 
 
192
  OUTL (devc->osdev, reg << 16 | data, devc->base + 0x20);
 
193
 
 
194
  for (i = 0; i < 100; i++)
 
195
    {
 
196
      status = INB (devc->osdev, devc->base + 0x38);
 
197
      if (status & 0x01)
 
198
        break;
 
199
    }
 
200
 
 
201
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
202
  return 1;
 
203
}
 
204
 
 
205
static int
 
206
ALIintr (oss_device_t * osdev)
 
207
{
 
208
  int status, global_status, p, f, i;
 
209
  int serviced = 0;
 
210
  ALI_devc *devc = (ALI_devc *) osdev->devc;
 
211
  ALI_portc *portc;
 
212
  /* oss_native_word flags; */
 
213
 
 
214
  /* Handle playback */
 
215
  /*
 
216
   * TODO: Fix mutexes and move the inputintr/outputintr calls outside the
 
217
   * mutex block.
 
218
   */
 
219
 
 
220
  /* MUTEX_ENTER (devc->mutex, flags); */
 
221
  /* Handle Global Interrupts */
 
222
  global_status = INL (devc->osdev, devc->base + 0x18);
 
223
  OUTL (devc->osdev, global_status, devc->base + 0x18);
 
224
 
 
225
  if (!(global_status & (0x10000 | 0x20000 | 0x80000 | 0x100000 | 0x200000)))
 
226
    {
 
227
      /* MUTEX_EXIT (devc->mutex, flags); */
 
228
      return serviced;
 
229
    }
 
230
 
 
231
  /* Handle Playback Interrupts */
 
232
 
 
233
  status = INB (devc->osdev, devc->base + 0x56);
 
234
 
 
235
  if ((status & 0x08) && (global_status & 0x20000))
 
236
    for (i = 0; i < MAX_PORTC - 1; i++)
 
237
      {
 
238
        portc = &devc->portc[i];
 
239
        serviced = 1;
 
240
        if ((portc->trigger_bits & PCM_ENABLE_OUTPUT))  /* IOC interrupt */
 
241
          {
 
242
            dmap_t *dmap = audio_engines[portc->audiodev]->dmap_out;
 
243
            p = INB (devc->osdev, devc->base + 0x54);
 
244
 
 
245
            if (p != devc->play_currbuf)
 
246
              {
 
247
                p = devc->play_currbuf;
 
248
                f = devc->play_currfrag;
 
249
                devc->playBDL[p].addr =
 
250
                  SWAP32 (dmap->dmabuf_phys + (f * dmap->fragment_size));
 
251
 
 
252
                devc->playBDL[p].size = SWAP16 (dmap->fragment_size / 2);
 
253
                devc->playBDL[p].flags = SWAP16 (0xc000);       /* IOC interrupts */
 
254
 
 
255
                OUTB (devc->osdev, p, devc->base + 0x55);       /* Set LVD */
 
256
                devc->play_frag_index[p] = f;
 
257
                devc->play_currbuf = (p + 1) % BDL_SIZE;
 
258
                devc->play_currfrag = (f + 1) % dmap->nfrags;
 
259
              }
 
260
            oss_audio_outputintr (portc->audiodev, 1);
 
261
          }
 
262
      }
 
263
  OUTB (devc->osdev, status, devc->base + 0x56);        /* Clear interrupts */
 
264
 
 
265
/*--------------------------------------------------------------------------*/
 
266
  /* handle SPDIF interrupts */
 
267
 
 
268
  status = INB (devc->osdev, devc->base + 0x76);
 
269
  if ((status & 0x08) && (global_status & 0x80000))
 
270
    {
 
271
      portc = &devc->portc[2];
 
272
      serviced = 1;
 
273
      if ((portc->trigger_bits & PCM_ENABLE_OUTPUT))    /* IOC interrupt */
 
274
        {
 
275
          dmap_t *dmap = audio_engines[portc->audiodev]->dmap_out;
 
276
          p = INB (devc->osdev, devc->base + 0x74);
 
277
 
 
278
          if (p != devc->spdif_currbuf)
 
279
            {
 
280
              p = devc->spdif_currbuf;
 
281
              f = devc->spdif_currfrag;
 
282
              devc->spdifBDL[p].addr =
 
283
                SWAP32 (dmap->dmabuf_phys + (f * dmap->fragment_size));
 
284
 
 
285
              devc->spdifBDL[p].size = SWAP16 (dmap->fragment_size / 2);
 
286
              devc->spdifBDL[p].flags = SWAP16 (0xc000);        /* IOC interrupts */
 
287
 
 
288
              OUTB (devc->osdev, p, devc->base + 0x75); /* Set LVD */
 
289
              devc->spdif_frag_index[p] = f;
 
290
              devc->spdif_currbuf = (p + 1) % BDL_SIZE;
 
291
              devc->spdif_currfrag = (f + 1) % dmap->nfrags;
 
292
            }
 
293
          oss_audio_outputintr (portc->audiodev, 1);
 
294
        }
 
295
    }
 
296
  OUTB (devc->osdev, status, devc->base + 0x76);        /* Clear interrupts */
 
297
/*---------------------------------------------------------------------------*/
 
298
 
 
299
  /* Handle Recording Interrupts */
 
300
  status = INB (devc->osdev, devc->base + 0x46);
 
301
 
 
302
  if ((status & 0x08) && (global_status & 0x10000))
 
303
    for (i = 0; i < MAX_PORTC - 1; i++)
 
304
      {
 
305
        portc = &devc->portc[i];
 
306
        serviced = 1;
 
307
        if ((portc->trigger_bits & PCM_ENABLE_INPUT))   /* IOC interrupt */
 
308
          {
 
309
            dmap_t *dmap = audio_engines[portc->audiodev]->dmap_in;
 
310
            p = INB (devc->osdev, devc->base + 0x44);
 
311
 
 
312
            if (p != devc->rec_currbuf)
 
313
              {
 
314
                p = devc->rec_currbuf;
 
315
                f = devc->rec_currfrag;
 
316
                devc->recBDL[p].addr =
 
317
                  SWAP32 (dmap->dmabuf_phys + (f * dmap->fragment_size));
 
318
 
 
319
                /* SIS uses bytes, ali5455 uses samples */
 
320
                devc->recBDL[p].size = SWAP16 (dmap->fragment_size / 2);
 
321
 
 
322
                devc->recBDL[p].flags = SWAP16 (0xc000);        /* IOC interrupts */
 
323
 
 
324
                OUTB (devc->osdev, p, devc->base + 0x45);       /* Set LVD */
 
325
                devc->rec_frag_index[p] = f;
 
326
                devc->rec_currbuf = (p + 1) % BDL_SIZE;
 
327
                devc->rec_currfrag = (f + 1) % dmap->nfrags;
 
328
              }
 
329
            oss_audio_inputintr (portc->audiodev, 0);
 
330
          }
 
331
      }
 
332
  OUTB (devc->osdev, status, devc->base + 0x46);        /* Clear int */
 
333
 
 
334
  /* MUTEX_EXIT (devc->mutex, flags); */
 
335
  return serviced;
 
336
}
 
337
 
 
338
/*
 
339
 * Audio routines
 
340
 */
 
341
 
 
342
static int
 
343
ALI_audio_set_rate (int dev, int arg)
 
344
{
 
345
  ALI_portc *portc = audio_engines[dev]->portc;
 
346
 
 
347
  if (arg == 0)
 
348
    return portc->speed;
 
349
 
 
350
  if (audio_engines[dev]->flags & ADEV_FIXEDRATE)
 
351
    arg = 48000;
 
352
 
 
353
  if (arg > 48000)
 
354
    arg = 48000;
 
355
  if (arg < 5000)
 
356
    arg = 5000;
 
357
  portc->speed = arg;
 
358
  return portc->speed;
 
359
}
 
360
 
 
361
static short
 
362
ALI_audio_set_channels (int dev, short arg)
 
363
{
 
364
  ALI_portc *portc = audio_engines[dev]->portc;
 
365
 
 
366
  if ((arg == 1) || (arg == 2))
 
367
    {
 
368
      audio_engines[dev]->flags |= ADEV_STEREOONLY;
 
369
      arg = 2;
 
370
    }
 
371
  else
 
372
    audio_engines[dev]->flags &= ~ADEV_STEREOONLY;
 
373
 
 
374
  if (arg>6)
 
375
     arg=6;
 
376
 
 
377
  if ((arg != 1) && (arg != 2) && (arg != 4) && (arg != 6))
 
378
    return portc->channels;
 
379
  portc->channels = arg;
 
380
 
 
381
  return portc->channels;
 
382
}
 
383
 
 
384
static unsigned int
 
385
ALI_audio_set_format (int dev, unsigned int arg)
 
386
{
 
387
  ALI_portc *portc = audio_engines[dev]->portc;
 
388
 
 
389
  if (arg == 0)
 
390
    return portc->bits;
 
391
 
 
392
  if (!(arg & (AFMT_U8 | AFMT_S16_LE | AFMT_AC3)))
 
393
    return portc->bits;
 
394
  portc->bits = arg;
 
395
 
 
396
  return portc->bits;
 
397
}
 
398
 
 
399
/*ARGSUSED*/
 
400
static int
 
401
ALI_audio_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
 
402
{
 
403
  return OSS_EINVAL;
 
404
}
 
405
 
 
406
static void ALI_audio_trigger (int dev, int state);
 
407
 
 
408
static void
 
409
ALI_audio_reset (int dev)
 
410
{
 
411
  ALI_audio_trigger (dev, 0);
 
412
}
 
413
 
 
414
static void
 
415
ALI_audio_reset_input (int dev)
 
416
{
 
417
  ALI_portc *portc = audio_engines[dev]->portc;
 
418
  ALI_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_INPUT);
 
419
}
 
420
 
 
421
static void
 
422
ALI_audio_reset_output (int dev)
 
423
{
 
424
  ALI_portc *portc = audio_engines[dev]->portc;
 
425
  ALI_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_OUTPUT);
 
426
}
 
427
 
 
428
/*ARGSUSED*/
 
429
static int
 
430
ALI_audio_open (int dev, int mode, int openflags)
 
431
{
 
432
  ALI_portc *portc = audio_engines[dev]->portc;
 
433
  ALI_devc *devc = audio_engines[dev]->devc;
 
434
  oss_native_word flags;
 
435
 
 
436
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
437
  if (portc->open_mode)
 
438
    {
 
439
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
440
      return OSS_EBUSY;
 
441
    }
 
442
 
 
443
  if (portc->port_type == DF_SPDIF)
 
444
    {
 
445
      if (mode & OPEN_READ)
 
446
        {
 
447
          cmn_err (CE_WARN,
 
448
                   "ICH: The S/PDIF device supports only playback\n");
 
449
          MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
450
          return OSS_EIO;
 
451
        }
 
452
    }
 
453
  else
 
454
    {
 
455
      if (devc->open_mode & mode)
 
456
        {
 
457
          MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
458
          return OSS_EBUSY;
 
459
        }
 
460
 
 
461
      devc->open_mode |= mode;
 
462
    }
 
463
 
 
464
 
 
465
  portc->open_mode = mode;
 
466
  portc->audio_enabled &= ~mode;
 
467
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
468
 
 
469
  return 0;
 
470
}
 
471
 
 
472
static void
 
473
ALI_audio_close (int dev, int mode)
 
474
{
 
475
  ALI_portc *portc = audio_engines[dev]->portc;
 
476
  ALI_devc *devc = audio_engines[dev]->devc;
 
477
 
 
478
  ALI_audio_reset (dev);
 
479
  portc->open_mode = 0;
 
480
 
 
481
  if (portc->port_type != DF_SPDIF)
 
482
    devc->open_mode &= ~mode;
 
483
 
 
484
 
 
485
  portc->audio_enabled &= ~mode;
 
486
}
 
487
 
 
488
/*ARGSUSED*/
 
489
static void
 
490
ALI_audio_output_block (int dev, oss_native_word buf, int count,
 
491
                        int fragsize, int intrflag)
 
492
{
 
493
  ALI_portc *portc = audio_engines[dev]->portc;
 
494
 
 
495
  portc->audio_enabled |= PCM_ENABLE_OUTPUT;
 
496
  portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
497
}
 
498
 
 
499
/*ARGSUSED*/
 
500
static void
 
501
ALI_audio_start_input (int dev, oss_native_word buf, int count,
 
502
                       int fragsize, int intrflag)
 
503
{
 
504
  ALI_portc *portc = audio_engines[dev]->portc;
 
505
 
 
506
  portc->audio_enabled |= PCM_ENABLE_INPUT;
 
507
  portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
508
}
 
509
 
 
510
static void
 
511
ALI_audio_trigger (int dev, int state)
 
512
{
 
513
  ALI_devc *devc = audio_engines[dev]->devc;
 
514
  ALI_portc *portc = audio_engines[dev]->portc;
 
515
  oss_native_word flags;
 
516
 
 
517
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
518
 
 
519
  if (portc->open_mode & OPEN_WRITE)
 
520
    {
 
521
      if (state & PCM_ENABLE_OUTPUT)
 
522
        {
 
523
          if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) &&
 
524
              !(portc->trigger_bits & PCM_ENABLE_OUTPUT))
 
525
            {
 
526
              if (portc->port_type == DF_SPDIF)
 
527
                {
 
528
                  OUTB (devc->osdev, 0x1d, devc->base + 0x7b);  /* Setup intr */
 
529
                  OUTW (devc->osdev, INW (devc->osdev, devc->base + 0x08) | 0x08, devc->base + 0x08);   /* start DMA */
 
530
                }
 
531
 
 
532
              if (portc->port_type == DF_PCM)
 
533
                {
 
534
                  OUTB (devc->osdev, 0x1d, devc->base + 0x5b);  /* setup intr */
 
535
                  OUTW (devc->osdev, INW (devc->osdev, devc->base + 0x08) | 0x02, devc->base + 0x08);   /* start DMA */
 
536
                }
 
537
              portc->trigger_bits |= PCM_ENABLE_OUTPUT;
 
538
            }
 
539
        }
 
540
      else
 
541
        {
 
542
          if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) &&
 
543
              (portc->trigger_bits & PCM_ENABLE_OUTPUT))
 
544
            {
 
545
              portc->audio_enabled &= ~PCM_ENABLE_OUTPUT;
 
546
              portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
547
              if (portc->port_type == DF_SPDIF)
 
548
                {
 
549
                  OUTB (devc->osdev, 0x00, devc->base + 0x7b);  /* reset */
 
550
                  OUTW (devc->osdev, INW (devc->osdev, devc->base + 0x08) & ~0x08, devc->base + 0x08);  /* stop DMA */
 
551
                }
 
552
 
 
553
              if (portc->port_type == DF_PCM)
 
554
                {
 
555
                  OUTB (devc->osdev, 0x00, devc->base + 0x5b);  /* reset */
 
556
                  OUTW (devc->osdev, INW (devc->osdev, devc->base + 0x08) & ~0x02, devc->base + 0x08);  /* stop DMA */
 
557
                }
 
558
            }
 
559
        }
 
560
    }
 
561
 
 
562
  if (portc->open_mode & OPEN_READ)
 
563
    {
 
564
      if (state & PCM_ENABLE_INPUT)
 
565
        {
 
566
          if ((portc->audio_enabled & PCM_ENABLE_INPUT) &&
 
567
              !(portc->trigger_bits & PCM_ENABLE_INPUT))
 
568
            {
 
569
              OUTB (devc->osdev, 0x1d, devc->base + 0x4b);      /* Kickstart */
 
570
              OUTW (devc->osdev, INW (devc->osdev, devc->base + 0x08) | 0x01, devc->base + 0x08);       /* stop DMA */
 
571
              portc->trigger_bits |= PCM_ENABLE_INPUT;
 
572
            }
 
573
        }
 
574
      else
 
575
        {
 
576
          if ((portc->audio_enabled & PCM_ENABLE_INPUT) &&
 
577
              (portc->trigger_bits & PCM_ENABLE_INPUT))
 
578
            {
 
579
              portc->audio_enabled &= ~PCM_ENABLE_INPUT;
 
580
              portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
581
              OUTB (devc->osdev, 0x00, devc->base + 0x4b);      /* reset */
 
582
              OUTW (devc->osdev, INW (devc->osdev, devc->base + 0x08) & ~0x01, devc->base + 0x08);      /* stop DMA */
 
583
            }
 
584
        }
 
585
    }
 
586
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
587
}
 
588
 
 
589
/*ARGSUSED*/
 
590
static int
 
591
ALI_audio_prepare_for_input (int dev, int bsize, int bcount)
 
592
{
 
593
  ALI_devc *devc = audio_engines[dev]->devc;
 
594
  ALI_portc *portc = audio_engines[dev]->portc;
 
595
  dmap_t *dmap = audio_engines[dev]->dmap_in;
 
596
  int i, n;
 
597
  oss_native_word flags;
 
598
 
 
599
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
600
 
 
601
  OUTB (devc->osdev, 0x02, devc->base + 0x4b);  /* Reset */
 
602
  OUTL (devc->osdev, devc->recBDL_phys, devc->base + 0x40);     /* BDL base */
 
603
 
 
604
  ac97_recrate (&devc->ac97devc, portc->speed);
 
605
 
 
606
  n = bcount;
 
607
  if (n > BDL_SIZE)
 
608
    n = BDL_SIZE;
 
609
 
 
610
  for (i = 0; i < n; i++)
 
611
    {
 
612
      devc->recBDL[i].addr =
 
613
        SWAP32 (dmap->dmabuf_phys + (i * dmap->fragment_size));
 
614
      devc->recBDL[i].size = SWAP16 (dmap->fragment_size / 2);
 
615
      devc->recBDL[i].flags = SWAP16 (0xc000);  /* IOC interrupts */
 
616
      devc->rec_frag_index[i] = i;
 
617
    }
 
618
  OUTB (devc->osdev, n - 1, devc->base + 0x45); /* Set last valid descriptor */
 
619
 
 
620
  devc->rec_currbuf = n % BDL_SIZE;
 
621
  devc->rec_currfrag = n;
 
622
  if (devc->rec_currfrag >= dmap->nfrags)
 
623
    devc->rec_currfrag = 0;
 
624
 
 
625
  portc->audio_enabled &= ~PCM_ENABLE_INPUT;
 
626
  portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
627
 
 
628
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
629
  return 0;
 
630
}
 
631
 
 
632
/*ARGSUSED*/
 
633
static int
 
634
ALI_audio_prepare_for_output (int dev, int bsize, int bcount)
 
635
{
 
636
  ALI_devc *devc = audio_engines[dev]->devc;
 
637
  ALI_portc *portc = audio_engines[dev]->portc;
 
638
  dmap_t *dmap = audio_engines[dev]->dmap_out;
 
639
  int i, n;
 
640
  oss_native_word flags;
 
641
 
 
642
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
643
 
 
644
  ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_AUDIO, SNDCTL_MIX_WRITE, 0);
 
645
  ac97_spdif_setup (devc->mixer_dev, portc->speed, portc->bits);
 
646
 
 
647
  if (portc->bits == AFMT_AC3)
 
648
    {
 
649
      portc->channels = 2;
 
650
      portc->bits = 16;
 
651
    }
 
652
 
 
653
  /* do SPDIF out */
 
654
  if (portc->port_type == DF_SPDIF)
 
655
    {
 
656
      ac97_playrate (&devc->ac97devc, portc->speed);
 
657
      OUTB (devc->osdev, 0x02, devc->base + 0x7b);      /* Reset */
 
658
      OUTL (devc->osdev, devc->spdifBDL_phys, devc->base + 0x70);
 
659
 
 
660
      n = bcount;
 
661
      if (n > BDL_SIZE)
 
662
        n = BDL_SIZE;
 
663
 
 
664
      for (i = 0; i < n; i++)
 
665
        {
 
666
          devc->spdifBDL[i].addr =
 
667
            SWAP32 (dmap->dmabuf_phys + (i * dmap->fragment_size));
 
668
          devc->spdifBDL[i].size = SWAP16 (dmap->fragment_size / 2);
 
669
          devc->spdifBDL[i].flags = SWAP16 (0xc000);    /* IOC interrupts */
 
670
          devc->spdif_frag_index[i] = i;
 
671
        }
 
672
      OUTB (devc->osdev, n - 1, devc->base + 0x75);     /* Set LVI descriptor */
 
673
      devc->spdif_currbuf = n % BDL_SIZE;
 
674
      devc->spdif_currfrag = n;
 
675
      if (devc->spdif_currfrag >= dmap->nfrags)
 
676
        devc->spdif_currfrag = 0;
 
677
 
 
678
      portc->audio_enabled &= ~PCM_ENABLE_OUTPUT;
 
679
      portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
680
 
 
681
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
682
      return 0;
 
683
    }
 
684
 
 
685
  /* else do PCM */
 
686
  OUTB (devc->osdev, 0x02, devc->base + 0x5b);  /* Reset */
 
687
  OUTL (devc->osdev, devc->playBDL_phys, devc->base + 0x50);
 
688
 
 
689
  ac97_playrate (&devc->ac97devc, portc->speed);
 
690
 
 
691
  /* set default to 2 channel mode */
 
692
  if (portc->channels == 2)
 
693
    OUTW (devc->osdev, INW (devc->osdev, devc->base + 0x00) & ~0x300,
 
694
          devc->base + 0x00);
 
695
  if (portc->channels == 4)
 
696
    OUTW (devc->osdev,
 
697
          (INW (devc->osdev, devc->base + 0x00) & ~0x300) | 0x100,
 
698
          devc->base + 0x00);
 
699
  if (portc->channels == 6)
 
700
    OUTW (devc->osdev,
 
701
          (INW (devc->osdev, devc->base + 0x00) & ~0x300) | 0x200,
 
702
          devc->base + 0x00);
 
703
 
 
704
 
 
705
  n = bcount;
 
706
  if (n > BDL_SIZE)
 
707
    n = BDL_SIZE;
 
708
 
 
709
  for (i = 0; i < n; i++)
 
710
    {
 
711
      devc->playBDL[i].addr =
 
712
        SWAP32 (dmap->dmabuf_phys + (i * dmap->fragment_size));
 
713
      devc->playBDL[i].size = SWAP16 (dmap->fragment_size / 2);
 
714
      devc->playBDL[i].flags = SWAP16 (0xc000); /* IOC interrupts */
 
715
      devc->play_frag_index[i] = i;
 
716
    }
 
717
  OUTB (devc->osdev, n - 1, devc->base + 0x55); /* Set last valid descriptor */
 
718
 
 
719
  devc->play_currbuf = n % BDL_SIZE;
 
720
  devc->play_currfrag = n;
 
721
  if (devc->play_currfrag >= dmap->nfrags)
 
722
    devc->play_currfrag = 0;
 
723
 
 
724
  portc->audio_enabled &= ~PCM_ENABLE_OUTPUT;
 
725
  portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
726
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
727
  return 0;
 
728
}
 
729
 
 
730
static const audiodrv_t ALI_audio_driver = {
 
731
  ALI_audio_open,
 
732
  ALI_audio_close,
 
733
  ALI_audio_output_block,
 
734
  ALI_audio_start_input,
 
735
  ALI_audio_ioctl,
 
736
  ALI_audio_prepare_for_input,
 
737
  ALI_audio_prepare_for_output,
 
738
  ALI_audio_reset,
 
739
  NULL,
 
740
  NULL,
 
741
  ALI_audio_reset_input,
 
742
  ALI_audio_reset_output,
 
743
  ALI_audio_trigger,
 
744
  ALI_audio_set_rate,
 
745
  ALI_audio_set_format,
 
746
  ALI_audio_set_channels
 
747
};
 
748
 
 
749
static int
 
750
init_ALI (ALI_devc * devc)
 
751
{
 
752
  int my_mixer, my_dev, opts;
 
753
  oss_native_word phaddr;
 
754
  int i;
 
755
 
 
756
  /* ACLink on, warm reset */
 
757
  OUTL (devc->osdev, 0x80008003, devc->base + 0x00);    /*reset SCR */
 
758
  OUTL (devc->osdev, 0x83838383, devc->base + 0x0c);    /*reset pcm in/out FIFO */
 
759
  OUTL (devc->osdev, 0x83838383, devc->base + 0x1c);    /*reset SPDIF/LFEr FIFO */
 
760
  OUTL (devc->osdev, 0x0028000a, devc->base + 0x10);    /*set spdif/pcm in/out */
 
761
  OUTL (devc->osdev, INL (devc->osdev, devc->base + 0xFC) | 0x3,
 
762
        devc->base + 0xFC);
 
763
 
 
764
  /* set up Codec SPDIFOUT slot to 10/11 */
 
765
  OUTL (devc->osdev, INL (devc->osdev, devc->base + 0x00) | 0x300000,
 
766
        devc->base + 0x00);
 
767
  /* disable interrupts */
 
768
  OUTL (devc->osdev, 0x00, devc->base + 0x14);
 
769
  OUTL (devc->osdev, 0x00, devc->base + 0x18);
 
770
 
 
771
  devc->bdlBuffer =
 
772
    CONTIG_MALLOC (devc->osdev, 4 * 32 * 32, MEMLIMIT_32BITS, &phaddr, devc->bdl_dma_handle);
 
773
  if (devc->bdlBuffer == NULL)
 
774
    {
 
775
      cmn_err (CE_WARN, "Failed to allocate BDL\n");
 
776
      return 0;
 
777
    }
 
778
 
 
779
  devc->playBDL = (bdl_t *) devc->bdlBuffer;
 
780
  devc->playBDL_phys = phaddr;
 
781
  devc->recBDL = (bdl_t *) (devc->bdlBuffer + (1 * 32 * 32));
 
782
  devc->recBDL_phys = phaddr + (1 * 32 * 32);
 
783
  devc->spdifBDL = (bdl_t *) (devc->bdlBuffer + (2 * 32 * 32));
 
784
  devc->spdifBDL_phys = phaddr + (2 * 32 * 32);
 
785
 
 
786
/*
 
787
 * Init mixer
 
788
 */
 
789
  my_mixer =
 
790
    ac97_install (&devc->ac97devc, "AC97 Mixer", ac97_read, ac97_write, devc,
 
791
                  devc->osdev);
 
792
 
 
793
  if (my_mixer == -1)
 
794
    return 0;                   /* No mixer */
 
795
 
 
796
  devc->mixer_dev = my_mixer;
 
797
 
 
798
  /* enable S/PDIF */
 
799
  devc->ac97devc.spdif_slot = SPDIF_SLOT1011;
 
800
  ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_ENABLE, SNDCTL_MIX_WRITE, 1);
 
801
 
 
802
#if 0
 
803
  /* enable variable rate mode */
 
804
  ac97_write (devc, 0x2a, ac97_read (devc, 0x2a) | 9);
 
805
  if (!(ac97_read (devc, 0x2a) & 1))
 
806
    DDB (cmn_err (CE_WARN, "VRA not supported...using GRC\n"));
 
807
#endif
 
808
 
 
809
  for (i = 0; i < MAX_PORTC; i++)
 
810
    {
 
811
      ALI_portc *portc = &devc->portc[i];
 
812
      char tmp_name[100];
 
813
      int port_fmt = DF_PCM;
 
814
      int formats = AFMT_S16_LE | AFMT_AC3;
 
815
      strcpy (tmp_name, devc->chip_name);
 
816
      opts = ADEV_AUTOMODE | ADEV_16BITONLY | ADEV_STEREOONLY;
 
817
      portc->port_type = DF_PCM;
 
818
 
 
819
      if (!ac97_varrate (&devc->ac97devc))
 
820
        {
 
821
          opts |= ADEV_FIXEDRATE;
 
822
        }
 
823
 
 
824
      if (i == 0)
 
825
        {
 
826
          opts |= ADEV_DUPLEX;
 
827
          strcpy (tmp_name, devc->chip_name);
 
828
        }
 
829
      if (i == 1)
 
830
        {
 
831
          opts |= ADEV_DUPLEX | ADEV_SHADOW;
 
832
          strcpy (tmp_name, devc->chip_name);
 
833
        }
 
834
 
 
835
      if (i == 2)
 
836
        {
 
837
          sprintf (tmp_name, "%s (S/PDIF)", devc->chip_name);
 
838
          opts |= ADEV_NOINPUT | ADEV_SPECIAL | ADEV_FIXEDRATE;
 
839
          port_fmt = DF_SPDIF;
 
840
        }
 
841
 
 
842
      if ((my_dev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION,
 
843
                                          devc->osdev,
 
844
                                          devc->osdev,
 
845
                                          tmp_name,
 
846
                                          &ALI_audio_driver,
 
847
                                          sizeof (audiodrv_t), opts,
 
848
                                          formats, devc, -1)) < 0)
 
849
        {
 
850
          my_dev = -1;
 
851
          return 0;
 
852
        }
 
853
      else
 
854
        {
 
855
          audio_engines[my_dev]->portc = portc;
 
856
          audio_engines[my_dev]->mixer_dev = my_mixer;
 
857
          audio_engines[my_dev]->min_rate =
 
858
            (opts & ADEV_FIXEDRATE) ? 48000 : 5000;
 
859
          audio_engines[my_dev]->max_rate = 48000;
 
860
          audio_engines[my_dev]->caps |= PCM_CAP_FREERATE;
 
861
          /*audio_engines[my_dev]->min_block = 4096; */
 
862
          /*audio_engines[my_dev]->max_block = 4096; */
 
863
          audio_engines[my_dev]->min_channels = 2;
 
864
          audio_engines[my_dev]->max_channels = 6;
 
865
          portc->open_mode = 0;
 
866
          portc->audio_enabled = 0;
 
867
          portc->audiodev = my_dev;
 
868
          portc->port_type = port_fmt;
 
869
          if (audio_engines[my_dev]->flags & ADEV_FIXEDRATE)
 
870
            audio_engines[my_dev]->fixed_rate = 48000;
 
871
#ifdef CONFIG_OSS_VMIX
 
872
          if (i == 0)
 
873
             vmix_attach_audiodev(devc->osdev, my_dev, -1, 0);
 
874
#endif
 
875
        }
 
876
    }
 
877
  return 1;
 
878
}
 
879
 
 
880
 
 
881
int
 
882
oss_ali5455_attach (oss_device_t * osdev)
 
883
{
 
884
  unsigned char pci_irq_line, pci_revision /*, pci_latency */ ;
 
885
  unsigned short pci_command, vendor, device;
 
886
  unsigned int pci_ioaddr0;
 
887
  ALI_devc *devc;
 
888
 
 
889
  DDB (cmn_err (CE_WARN, "Entered ALI AC97 probe routine\n"));
 
890
 
 
891
  pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor);
 
892
  pci_read_config_word (osdev, PCI_DEVICE_ID, &device);
 
893
 
 
894
  if ((vendor != ALI_VENDOR_ID) || (device != ALI_DEVICE_5455))
 
895
    return 0;
 
896
 
 
897
  pci_read_config_byte (osdev, PCI_REVISION_ID, &pci_revision);
 
898
  pci_read_config_word (osdev, PCI_COMMAND, &pci_command);
 
899
  pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line);
 
900
  pci_read_config_dword (osdev, PCI_BASE_ADDRESS_0, &pci_ioaddr0);
 
901
 
 
902
  if (pci_ioaddr0 == 0)
 
903
    {
 
904
      cmn_err (CE_WARN, "I/O address not assigned by BIOS.\n");
 
905
      return 0;
 
906
    }
 
907
 
 
908
  if (pci_irq_line == 0)
 
909
    {
 
910
      cmn_err (CE_WARN, "IRQ not assigned by BIOS (%d).\n", pci_irq_line);
 
911
      return 0;
 
912
    }
 
913
 
 
914
  if ((devc = PMALLOC (osdev, sizeof (*devc))) == NULL)
 
915
    {
 
916
      cmn_err (CE_WARN, "Out of memory\n");
 
917
      return 0;
 
918
    }
 
919
 
 
920
  devc->osdev = osdev;
 
921
  osdev->devc = devc;
 
922
  devc->open_mode = 0;
 
923
 
 
924
  /* Remove I/O space marker in bit 0. */
 
925
  devc->base = MAP_PCI_IOADDR (devc->osdev, 0, pci_ioaddr0);
 
926
  devc->base &= ~0xF;
 
927
 
 
928
  pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
 
929
  pci_write_config_word (osdev, PCI_COMMAND, pci_command);
 
930
 
 
931
  devc->chip_name = "ALI M5455";
 
932
  devc->irq = pci_irq_line;
 
933
 
 
934
  MUTEX_INIT (devc->osdev, devc->mutex, MH_DRV);
 
935
  MUTEX_INIT (devc->osdev, devc->low_mutex, MH_DRV + 1);
 
936
 
 
937
  oss_register_device (osdev, devc->chip_name);
 
938
 
 
939
  if (oss_register_interrupts (devc->osdev, 0, ALIintr, NULL) < 0)
 
940
    {
 
941
      cmn_err (CE_WARN, "Unable to install interrupt handler\n");
 
942
      return 0;
 
943
    }
 
944
 
 
945
  return init_ALI (devc);       /* Detected */
 
946
}
 
947
 
 
948
 
 
949
int
 
950
oss_ali5455_detach (oss_device_t * osdev)
 
951
{
 
952
  ALI_devc *devc = (ALI_devc *) osdev->devc;
 
953
 
 
954
 
 
955
  if (oss_disable_device (osdev) < 0)
 
956
    return 0;
 
957
 
 
958
  /* disable S/PDIF */
 
959
  if (devc->mixer_dev)
 
960
    ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_ENABLE, SNDCTL_MIX_WRITE, 0);
 
961
  /* disable interrupts */
 
962
  OUTL (devc->osdev, 0x00, devc->base + 0x14);
 
963
  OUTL (devc->osdev, 0x00, devc->base + 0x18);
 
964
 
 
965
  oss_unregister_interrupts (devc->osdev);
 
966
 
 
967
  if (devc->bdlBuffer)
 
968
    {
 
969
      CONTIG_FREE (devc->osdev, devc->bdlBuffer, 4 * 32 * 32, devc->bdl_dma_handle);
 
970
      devc->bdlBuffer = NULL;
 
971
    }
 
972
 
 
973
  MUTEX_CLEANUP (devc->mutex);
 
974
  MUTEX_CLEANUP (devc->low_mutex);
 
975
  UNMAP_PCI_IOADDR (devc->osdev, 0);
 
976
 
 
977
  oss_unregister_device (osdev);
 
978
  return 1;
 
979
}