~ubuntu-branches/ubuntu/vivid/oss4/vivid-proposed

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Romain Beauxis, Samuel Thibault, Romain Beauxis, Sebastien NOEL
  • Date: 2011-06-14 10:06:56 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110614100656-cx4oc7u426zn812z
Tags: 4.2-build2004-1
[ Samuel Thibault ]
* debian/control: Add liboss4-salsa2, liboss4-salsa-dev and
  liboss4-salsa-asound2 packages, equivalent to (and will replace) those from
  the oss-libsalsa package (Closes: #589127).
* debian/patches/liboss4-salsa.patch: New patch to rename libsalsa into
  liboss4-salsa to avoid conflicts in the archive for no good reason.
* debian/rules: Make in libOSSlib and libsalsa.
* debian/liboss4-salsa-dev.install, debian/liboss4-salsa2.install,
  debian/liboss4-salsa-asound2.links, debian/liboss4-salsa-dev.links:
  Install liboss4-salsa libraries like was done in the oss-libsalsa package.
* include-alsa: Add a copy of ALSA 1.0.5 headers: Cf ALSA_1.0.* symbols in
  libsalsa, this is the roughly supported version.
* debian/copyright: Update for new include-alsa files.
* alsa.pc: New file for compatibility with libasound-dev.
* debian/control:
  - Add Vcs-Browser and Vcs-Svn fields.
  - Use linux-any instead of the list of Linux archs (Closes: #604679).
  - Make dkms dependency linux-any only.
* debian/patches/hurd_iot.patch: New patch to fix soundcard.h usage in
  libsalsa on hurd-i386.
* debian/patches/libsalsa_fixes.patch: New patch to fix some printf usages
  and ioctl declaration in libsalsa.
* debian/patches/no_EBADE.patch: New patch to cope with hurd-i386 not having
  EBADE.
* debian/patches/CFLAGS.patch: New patch to make oss4 take debian/rules
  CFLAGS into account.
* debian/patches/snd_asoundlib_version.patch: New patch to add
  snd_asoundlib_version().
* debian/patches/generic_srccconf.patch: New patch to fix source
  configuration on unknown archs.

[ Romain Beauxis ]
* Fixed README.Debian to only mention dkms' modules.
* Switch to dpkg-source 3.0 (quilt) format
* Added DM-Upload-Allowed: yes

[ Sebastien NOEL ]
* New upstream release (Closes: #595298, #619272).
* Fix typo in initscript (Closes: #627149).
* debian/control: adjust linux-headers dependencies (Closes: #628879).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Purpose: Driver for the VIA8233/8235 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_via823x_cfg.h"
 
17
#include <oss_pci.h>
 
18
#include <ac97.h>
 
19
#include "via8233.h"
 
20
 
 
21
 
 
22
static void feed_sgd (via8233_devc * devc, dmap_t * dmap, engine_desc * eng);
 
23
 
 
24
static int
 
25
ac97_read (void *devc_, int wIndex)
 
26
{
 
27
  oss_native_word flags;
 
28
  unsigned int dwWriteValue = 0, dwTmpValue, i = 0;
 
29
  via8233_devc *devc = devc_;
 
30
 
 
31
 
 
32
  /* Index has only 7 bit */
 
33
  if (wIndex > 0x7F)
 
34
    return 0;
 
35
 
 
36
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
37
  dwWriteValue = ((unsigned int) wIndex << 16) + CODEC_RD;
 
38
  OUTL (devc->osdev, dwWriteValue, devc->base + AC97CODEC);
 
39
  oss_udelay (100);
 
40
  /* Check AC CODEC access time out */
 
41
  for (i = 0; i < CODEC_TIMEOUT_COUNT; i++)
 
42
    {
 
43
      /* if send command over, break */
 
44
      if (INL (devc->osdev, devc->base + AC97CODEC) & STA_VALID)
 
45
        break;
 
46
      oss_udelay (50);
 
47
    }
 
48
  if (i == CODEC_TIMEOUT_COUNT)
 
49
    {
 
50
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
51
      return OSS_EIO;
 
52
    }
 
53
 
 
54
  /* Check if Index still ours? If yes, return data, else return FAIL */
 
55
  dwTmpValue = INL (devc->osdev, devc->base + AC97CODEC);
 
56
  OUTB (devc->osdev, 0x02, devc->base + AC97CODEC + 3);
 
57
  if (((dwTmpValue & CODEC_INDEX) >> 16) == wIndex)
 
58
    {
 
59
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
60
      return ((int) dwTmpValue & CODEC_DATA);
 
61
    }
 
62
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
63
  return OSS_EIO;
 
64
 
 
65
}
 
66
 
 
67
static int
 
68
ac97_write (void *devc_, int wIndex, int wData)
 
69
{
 
70
  oss_native_word flags;
 
71
  unsigned int dwWriteValue = 0, i = 0;
 
72
  via8233_devc *devc = devc_;
 
73
 
 
74
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
75
  dwWriteValue = ((unsigned int) wIndex << 16) + wData;
 
76
  OUTL (devc->osdev, dwWriteValue, devc->base + AC97CODEC);
 
77
  oss_udelay (100);
 
78
 
 
79
  /* Check AC CODEC access time out */
 
80
  for (i = 0; i < CODEC_TIMEOUT_COUNT; i++)
 
81
    {
 
82
      /* if send command over, break */
 
83
      if (!(INL (devc->osdev, devc->base + AC97CODEC) & IN_CMD))
 
84
        break;
 
85
      oss_udelay (50);
 
86
    }
 
87
  if (i == CODEC_TIMEOUT_COUNT)
 
88
    {
 
89
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
90
      return 0;
 
91
    }
 
92
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
93
  return 1;
 
94
}
 
95
 
 
96
static int
 
97
via8233intr (oss_device_t * osdev)
 
98
{
 
99
  int serviced = 0, i;
 
100
  via8233_devc *devc = osdev->devc;
 
101
  via8233_portc *portc;
 
102
  engine_desc *eng;
 
103
  unsigned int engine_stat;
 
104
  unsigned int status = 0;
 
105
  oss_native_word flags;
 
106
 
 
107
  MUTEX_ENTER (devc->mutex, flags);
 
108
  status = INL (devc->osdev, devc->base + 0x84);
 
109
#if 0
 
110
  // This is reported to cause hang because some status register bits
 
111
  // may be turned on even ehen the device is not interrupting.
 
112
  if (status == 0)
 
113
    {
 
114
      /*
 
115
       * No interrupts are pending so we can stop without
 
116
       * polling all the individual status registers.
 
117
       */
 
118
      MUTEX_EXIT (devc->mutex, flags);
 
119
      return 0;
 
120
    }
 
121
#endif
 
122
 
 
123
  for (i = 0; i < MAX_PORTC; i++)
 
124
    {
 
125
      portc = &devc->portc[i];
 
126
      eng = portc->play_engine;
 
127
 
 
128
      if (eng != NULL)
 
129
        if ((eng->mode & OPEN_WRITE)
 
130
            && (portc->trigger_bits & PCM_ENABLE_OUTPUT))
 
131
          {
 
132
            engine_stat = INB (devc->osdev, eng->base + 0x00);
 
133
            if (engine_stat & 0x01)
 
134
              {
 
135
                oss_audio_outputintr (portc->audiodev, 1);
 
136
                feed_sgd (devc, audio_engines[portc->audiodev]->dmap_out,
 
137
                          eng);
 
138
                serviced = 1;
 
139
              }
 
140
            OUTB (devc->osdev, engine_stat, eng->base + 0x00);
 
141
          }
 
142
 
 
143
      eng = portc->rec_engine;
 
144
      if (eng != NULL)
 
145
        if ((eng->mode & OPEN_READ)
 
146
            && (portc->trigger_bits & PCM_ENABLE_INPUT))
 
147
          {
 
148
            engine_stat = INB (devc->osdev, eng->base + 0x00);
 
149
            if (engine_stat & 0x01)
 
150
              {
 
151
                oss_audio_inputintr (portc->audiodev, 0);
 
152
                feed_sgd (devc, audio_engines[portc->audiodev]->dmap_in, eng);
 
153
                serviced = 1;
 
154
              }
 
155
            OUTB (devc->osdev, engine_stat, eng->base + 0x00);
 
156
          }
 
157
    }
 
158
  MUTEX_EXIT (devc->mutex, flags);
 
159
 
 
160
  return serviced;
 
161
}
 
162
 
 
163
/*
 
164
 * Audio routines
 
165
 */
 
166
 
 
167
static int
 
168
via8233_audio_set_rate (int dev, int arg)
 
169
{
 
170
  via8233_portc *portc = audio_engines[dev]->portc;
 
171
 
 
172
  if (arg == 0)
 
173
    return portc->speed;
 
174
 
 
175
  if (audio_engines[dev]->flags & ADEV_FIXEDRATE)
 
176
    arg = 48000;
 
177
 
 
178
  if (arg > 48000)
 
179
    arg = 48000;
 
180
  if (arg < 5000)
 
181
    arg = 5000;
 
182
  portc->speed = arg;
 
183
  return portc->speed;
 
184
}
 
185
 
 
186
static short
 
187
via8233_audio_set_channels (int dev, short arg)
 
188
{
 
189
  via8233_portc *portc = audio_engines[dev]->portc;
 
190
 
 
191
  if (arg > 6)
 
192
     arg=6;
 
193
 
 
194
  if ((arg != 1) && (arg != 2) && (arg != 4) && (arg != 6))
 
195
    return portc->channels;
 
196
  portc->channels = arg;
 
197
 
 
198
  return portc->channels;
 
199
}
 
200
 
 
201
static unsigned int
 
202
via8233_audio_set_format (int dev, unsigned int arg)
 
203
{
 
204
  via8233_portc *portc = audio_engines[dev]->portc;
 
205
 
 
206
  if (arg == 0)
 
207
    return portc->bits;
 
208
 
 
209
  if (!(arg & (AFMT_U8 | AFMT_S16_LE | AFMT_AC3)))
 
210
    return portc->bits;
 
211
  portc->bits = arg;
 
212
 
 
213
  return portc->bits;
 
214
}
 
215
 
 
216
/*ARGSUSED*/
 
217
static int
 
218
via8233_audio_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
 
219
{
 
220
  return OSS_EINVAL;
 
221
}
 
222
 
 
223
static void via8233_audio_trigger (int dev, int state);
 
224
 
 
225
static void
 
226
via8233_audio_reset (int dev)
 
227
{
 
228
  via8233_audio_trigger (dev, 0);
 
229
}
 
230
 
 
231
static void
 
232
via8233_audio_reset_input (int dev)
 
233
{
 
234
  via8233_portc *portc = audio_engines[dev]->portc;
 
235
  via8233_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_INPUT);
 
236
}
 
237
 
 
238
static void
 
239
via8233_audio_reset_output (int dev)
 
240
{
 
241
  via8233_portc *portc = audio_engines[dev]->portc;
 
242
  via8233_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_OUTPUT);
 
243
}
 
244
 
 
245
/*ARGSUSED*/
 
246
static int
 
247
via8233_audio_open (int dev, int mode, int open_flags)
 
248
{
 
249
  via8233_portc *portc = audio_engines[dev]->portc;
 
250
  via8233_devc *devc = audio_engines[dev]->devc;
 
251
  oss_native_word flags;
 
252
 
 
253
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
254
  if (portc->open_mode)
 
255
    {
 
256
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
257
      return OSS_EBUSY;
 
258
    }
 
259
 
 
260
  if (devc->open_mode & mode)
 
261
    {
 
262
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
263
      return OSS_EBUSY;
 
264
    }
 
265
 
 
266
  devc->open_mode |= mode;
 
267
 
 
268
  portc->open_mode = mode;
 
269
  portc->audio_enabled &= ~mode;
 
270
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
271
 
 
272
  return 0;
 
273
}
 
274
 
 
275
static void
 
276
via8233_audio_close (int dev, int mode)
 
277
{
 
278
  via8233_portc *portc = audio_engines[dev]->portc;
 
279
  via8233_devc *devc = audio_engines[dev]->devc;
 
280
 
 
281
  via8233_audio_reset (dev);
 
282
  portc->open_mode = 0;
 
283
  devc->open_mode &= ~mode;
 
284
  portc->audio_enabled &= ~mode;
 
285
}
 
286
 
 
287
/*ARGSUSED*/
 
288
static void
 
289
via8233_audio_output_block (int dev, oss_native_word buf, int count,
 
290
                            int fragsize, int intrflag)
 
291
{
 
292
  via8233_portc *portc = audio_engines[dev]->portc;
 
293
 
 
294
  portc->audio_enabled |= PCM_ENABLE_OUTPUT;
 
295
  portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
296
 
 
297
 
 
298
}
 
299
 
 
300
/*ARGSUSED*/
 
301
static void
 
302
via8233_audio_start_input (int dev, oss_native_word buf, int count,
 
303
                           int fragsize, int intrflag)
 
304
{
 
305
  via8233_portc *portc = audio_engines[dev]->portc;
 
306
 
 
307
  portc->audio_enabled |= PCM_ENABLE_INPUT;
 
308
  portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
309
 
 
310
}
 
311
 
 
312
static void
 
313
via8233_audio_trigger (int dev, int state)
 
314
{
 
315
  via8233_portc *portc = audio_engines[dev]->portc;
 
316
  via8233_devc *devc = audio_engines[dev]->devc;
 
317
  engine_desc *eng;
 
318
  oss_native_word flags;
 
319
 
 
320
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
321
  if ((portc->open_mode & OPEN_WRITE) && portc->play_engine != NULL)
 
322
    {
 
323
      eng = portc->play_engine;
 
324
 
 
325
      if (state & PCM_ENABLE_OUTPUT)
 
326
        {
 
327
          if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) &&
 
328
              !(portc->trigger_bits & PCM_ENABLE_OUTPUT))
 
329
            {
 
330
              /* Start with autoinit and SGD flag interrupts enabled */
 
331
              OUTB (devc->osdev, 0xa1, eng->base + 0x01);
 
332
              portc->trigger_bits |= PCM_ENABLE_OUTPUT;
 
333
            }
 
334
        }
 
335
      else
 
336
        {
 
337
          if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) &&
 
338
              (portc->trigger_bits & PCM_ENABLE_OUTPUT))
 
339
            {
 
340
              OUTB (devc->osdev, 0x40, eng->base + 0x01);       /* Stop */
 
341
              portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
342
            }
 
343
        }
 
344
    }
 
345
 
 
346
  if ((portc->open_mode & OPEN_READ) && portc->rec_engine != NULL)
 
347
    {
 
348
      eng = portc->rec_engine;
 
349
 
 
350
      if (state & PCM_ENABLE_INPUT)
 
351
        {
 
352
          if ((portc->audio_enabled & PCM_ENABLE_INPUT) &&
 
353
              !(portc->trigger_bits & PCM_ENABLE_INPUT))
 
354
            {
 
355
              /* Start with autoinit and SGD flag interrupts enabled */
 
356
              OUTB (devc->osdev, 0xa1, eng->base + 0x01);
 
357
              portc->trigger_bits |= PCM_ENABLE_INPUT;
 
358
            }
 
359
        }
 
360
      else
 
361
        {
 
362
          if ((portc->audio_enabled & PCM_ENABLE_INPUT) &&
 
363
              (portc->trigger_bits & PCM_ENABLE_INPUT))
 
364
            {
 
365
              portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
366
              OUTB (devc->osdev, 0x40, eng->base + 0x01);       /* Stop */
 
367
            }
 
368
        }
 
369
    }
 
370
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
371
}
 
372
 
 
373
static void
 
374
feed_sgd (via8233_devc * devc, dmap_t * dmap, engine_desc * eng)
 
375
{
 
376
  unsigned int addr, p, tmp;
 
377
  oss_native_word flags;
 
378
 
 
379
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
380
  addr = dmap->dmabuf_phys + eng->cfrag * dmap->fragment_size;
 
381
  p = eng->sgd_ptr;
 
382
 
 
383
  eng->sgd[p].phaddr = addr;
 
384
  eng->sgd[p].flags = dmap->fragment_size | SGD_FLAG;
 
385
  if (p == (SGD_SIZE - 1))
 
386
    eng->sgd[p].flags |= SGD_EOL;
 
387
 
 
388
  /* Update the last entry ptr */
 
389
  tmp = INL (devc->osdev, eng->base + 0x08);
 
390
  tmp &= 0x00ffffff;
 
391
  tmp |= (p << 24);
 
392
  OUTL (devc->osdev, tmp, eng->base + 0x08);
 
393
 
 
394
  eng->prev_sgd = p;
 
395
  eng->frags[p] = eng->cfrag;
 
396
  eng->cfrag = (eng->cfrag + 1) % dmap->nfrags;
 
397
  eng->sgd_ptr = (eng->sgd_ptr + 1) % SGD_SIZE;
 
398
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
399
}
 
400
 
 
401
/*ARGSUSED*/
 
402
static int
 
403
via8233_audio_prepare_for_input (int dev, int bsize, int bcount)
 
404
{
 
405
  via8233_devc *devc = audio_engines[dev]->devc;
 
406
  via8233_portc *portc = audio_engines[dev]->portc;
 
407
  dmap_t *dmap = audio_engines[dev]->dmap_in;
 
408
  engine_desc *eng;
 
409
  int i;
 
410
  unsigned int fmt;
 
411
  oss_native_word flags;
 
412
 
 
413
  if (portc->rec_engine == NULL)
 
414
    {
 
415
      cmn_err (CE_WARN, "No rec engine (dev=%d)\n", dev);
 
416
      return OSS_EIO;
 
417
    }
 
418
 
 
419
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
420
  eng = portc->rec_engine;
 
421
 
 
422
  OUTB (devc->osdev, 0x40, eng->base + 0x01);   /* Stop */
 
423
 
 
424
  eng->cfrag = 0;
 
425
  eng->sgd_ptr = 0;
 
426
  eng->prevpos = 0xffffffff;
 
427
 
 
428
  for (i = 0; i < 2; i++)
 
429
    feed_sgd (devc, dmap, eng);
 
430
 
 
431
  OUTL (devc->osdev, eng->sgd_phys, eng->base + 0x04);
 
432
 
 
433
  fmt = 0;
 
434
  if (portc->bits == AFMT_S16_LE)
 
435
    fmt |= (1 << 21);
 
436
  if (portc->channels == 2)
 
437
    fmt |= (1 << 20);
 
438
 
 
439
  if (devc->chip_type != CHIP_8233A)
 
440
    {
 
441
      if (portc->speed == 48000)
 
442
        fmt |= (1 << 20) - 1;
 
443
      else
 
444
        fmt |= ((1024 * portc->speed + 24000) / 48000) * 1024;
 
445
    }
 
446
 
 
447
  fmt |= (eng->prev_sgd << 24);
 
448
  OUTL (devc->osdev, fmt, eng->base + 0x08);
 
449
  ac97_recrate (&devc->ac97devc, portc->speed);
 
450
 
 
451
  portc->audio_enabled &= ~PCM_ENABLE_INPUT;
 
452
  portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
453
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
454
  return 0;
 
455
}
 
456
 
 
457
/*ARGSUSED*/
 
458
static int
 
459
via8233_audio_prepare_for_output (int dev, int bsize, int bcount)
 
460
{
 
461
  via8233_devc *devc = audio_engines[dev]->devc;
 
462
  via8233_portc *portc = audio_engines[dev]->portc;
 
463
  dmap_p dmap = audio_engines[dev]->dmap_out;
 
464
 
 
465
  engine_desc *eng;
 
466
  int i, tmp;
 
467
  oss_native_word flags;
 
468
 
 
469
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
470
  eng = portc->play_engine;
 
471
 
 
472
  OUTB (devc->osdev, 0x40, eng->base + 0x01);   /* Stop */
 
473
 
 
474
  eng->cfrag = 0;
 
475
  eng->sgd_ptr = 0;
 
476
  eng->prevpos = 0xffffffff;
 
477
 
 
478
  for (i = 0; i < 2; i++)
 
479
    feed_sgd (devc, dmap, eng);
 
480
 
 
481
  OUTL (devc->osdev, eng->sgd_phys, eng->base + 0x4);
 
482
 
 
483
  ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_AUDIO, SNDCTL_MIX_WRITE, 0);
 
484
 
 
485
  if (portc->bits == AFMT_AC3)
 
486
    {
 
487
      portc->channels = 2;
 
488
      portc->bits = 16;
 
489
    }
 
490
  ac97_spdif_setup (devc->mixer_dev, portc->speed, portc->bits);
 
491
 
 
492
  tmp = (portc->bits == AFMT_U8) ? 0 : 0x80;
 
493
  tmp |= portc->channels << 4;
 
494
  OUTB (devc->osdev, tmp, eng->base + 0x02);
 
495
 
 
496
  /* Select channel assignment - not valid for 8233A */
 
497
  tmp = 0;
 
498
  if (devc->chip_type != CHIP_8233A)
 
499
    {
 
500
      switch (portc->channels)
 
501
        {
 
502
        case 1:
 
503
          tmp = (1 << 0) | (1 << 4);
 
504
          break;
 
505
        case 2:
 
506
          tmp = (1 << 0) | (2 << 4);
 
507
          break;
 
508
        case 4:
 
509
          tmp = (1 << 0) | (2 << 4) | (3 << 8) | (4 << 12);
 
510
          break;
 
511
        case 6:
 
512
          tmp =
 
513
            (1 << 0) | (2 << 4) | (5 << 8) | (6 << 12) | (3 << 16) | (4 <<
 
514
                                                                      20);
 
515
          break;
 
516
        default:
 
517
          tmp = 0;
 
518
          break;
 
519
        }
 
520
    }
 
521
  tmp |= 0xFF000000;
 
522
  OUTL (devc->osdev, tmp, eng->base + 0x08);
 
523
  /* need to set the speed twice - for some odd reason */
 
524
  ac97_playrate (&devc->ac97devc, portc->speed);
 
525
  ac97_playrate (&devc->ac97devc, portc->speed);
 
526
 
 
527
  portc->audio_enabled &= ~PCM_ENABLE_OUTPUT;
 
528
  portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
529
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
530
 
 
531
  return 0;
 
532
}
 
533
 
 
534
/*ARGSUSED*/
 
535
static int
 
536
via8233_alloc_buffer (int dev, dmap_t * dmap, int direction)
 
537
{
 
538
  int err;
 
539
  via8233_devc *devc = audio_engines[dev]->devc;
 
540
  via8233_portc *portc = audio_engines[dev]->portc;
 
541
  engine_desc *eng;
 
542
 
 
543
  if (dmap->dmabuf != NULL)
 
544
    return 0;
 
545
 
 
546
  if ((err = oss_alloc_dmabuf (dev, dmap, direction)) < 0)
 
547
    return err;
 
548
 
 
549
 
 
550
  if (direction == PCM_ENABLE_INPUT)
 
551
    {
 
552
      eng = &devc->engines[REC_SGD_NUM];
 
553
      eng->mode = OPEN_READ;
 
554
      portc->rec_engine = eng;
 
555
    }
 
556
  else
 
557
    {
 
558
      eng = &devc->engines[PLAY_SGD_NUM];
 
559
      eng->mode = OPEN_WRITE;
 
560
      portc->play_engine = eng;
 
561
    }
 
562
 
 
563
  return 0;
 
564
}
 
565
 
 
566
 
 
567
/*ARGSUSED*/
 
568
static int
 
569
via8233_free_buffer (int dev, dmap_t * dmap, int direction)
 
570
{
 
571
  via8233_portc *portc = audio_engines[dev]->portc;
 
572
 
 
573
  if (dmap->dmabuf == NULL)
 
574
    return 0;
 
575
  oss_free_dmabuf (dev, dmap);
 
576
 
 
577
  dmap->dmabuf = NULL;
 
578
  dmap->dmabuf_phys = 0;
 
579
 
 
580
  if (direction == PCM_ENABLE_OUTPUT)
 
581
    portc->play_engine = NULL;
 
582
 
 
583
  if (direction == PCM_ENABLE_INPUT)
 
584
    portc->rec_engine = NULL;
 
585
 
 
586
  return 0;
 
587
}
 
588
 
 
589
static int
 
590
via8233_get_buffer_pointer (int dev, dmap_t * dmap, int direction)
 
591
{
 
592
  via8233_portc *portc = audio_engines[dev]->portc;
 
593
  via8233_devc *devc = audio_engines[dev]->devc;
 
594
  unsigned int ptr, pos, tmp;
 
595
  engine_desc *eng;
 
596
  oss_native_word flags;
 
597
 
 
598
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
599
  if (direction == PCM_ENABLE_OUTPUT)
 
600
    {
 
601
      int status;
 
602
      /* int this_sgd, prev_sgd */ ;
 
603
 
 
604
      if (portc->play_engine == NULL
 
605
          || !(portc->trigger_bits & PCM_ENABLE_OUTPUT))
 
606
        {
 
607
          MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
608
          return 0;
 
609
        }
 
610
 
 
611
      eng = portc->play_engine;
 
612
 
 
613
      ptr = INL (devc->osdev, eng->base + 0x0c);
 
614
      status = INB (devc->osdev, eng->base + 0x00);
 
615
      if (!(status & 0x80))     /* SGD not triggered */
 
616
        {
 
617
          MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
618
          return 0;
 
619
        }
 
620
 
 
621
#ifdef DO_TIMINGS
 
622
      oss_timing_printf ("rawpos=%d", ptr);
 
623
#endif
 
624
#if 0
 
625
      this_sgd = ptr >> 24;
 
626
      prev_sgd = eng->prevpos >> 24;
 
627
      prev_sgd = (prev_sgd + 1) % SGD_SIZE;     /* Increment */
 
628
      /* Chip bug catcher */
 
629
      if (((ptr & 0xffffff) == 0) &&
 
630
          ((eng->prevpos & 0xffffff) == 0) && (this_sgd == prev_sgd))
 
631
        ptr = eng->prevpos;
 
632
      else
 
633
        eng->prevpos = ptr;
 
634
#endif
 
635
 
 
636
      tmp = ptr & 0xffffff;
 
637
      ptr >>= 24;
 
638
 
 
639
      pos = eng->frags[ptr] * dmap->fragment_size;
 
640
      pos += (dmap->fragment_size - tmp) & ~3;
 
641
 
 
642
#ifdef DO_TIMINGS
 
643
      oss_timing_printf ("Playpos=%d", pos);
 
644
#endif
 
645
      pos = pos % dmap->bytes_in_use;
 
646
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
647
      return pos;
 
648
    }
 
649
 
 
650
  if (direction == PCM_ENABLE_INPUT)
 
651
    {
 
652
      int status;
 
653
      /* int this_sgd, prev_sgd; */
 
654
 
 
655
      if (portc->rec_engine == NULL
 
656
          || !(portc->trigger_bits & PCM_ENABLE_INPUT))
 
657
        {
 
658
          MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
659
          return 0;
 
660
        }
 
661
 
 
662
      eng = portc->rec_engine;
 
663
 
 
664
      ptr = INL (devc->osdev, eng->base + 0x0c);
 
665
      status = INB (devc->osdev, eng->base + 0x00);
 
666
      if (!(status & 0x80))     /* SGD not triggered */
 
667
        {
 
668
          MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
669
          return 0;
 
670
        }
 
671
 
 
672
#if 0
 
673
      this_sgd = ptr >> 24;
 
674
      prev_sgd = eng->prevpos >> 24;
 
675
      prev_sgd = (prev_sgd + 1) % SGD_SIZE;     /* Increment */
 
676
 
 
677
      /* Chip bug catcher */
 
678
      if (((ptr & 0xffffff) == 0) &&
 
679
          ((eng->prevpos & 0xffffff) == 0) && (this_sgd == prev_sgd))
 
680
        ptr = eng->prevpos;
 
681
      else
 
682
        eng->prevpos = ptr;
 
683
#endif
 
684
 
 
685
      tmp = ptr & 0xffffff;
 
686
      ptr >>= 24;
 
687
 
 
688
      pos = eng->frags[ptr] * dmap->fragment_size;
 
689
      pos += (dmap->fragment_size - tmp) & ~3;
 
690
 
 
691
#ifdef DO_TIMINGS
 
692
      oss_timing_printf ("Recpos=%d", pos);
 
693
#endif
 
694
      pos = pos % dmap->bytes_in_use;
 
695
      MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
696
      return pos;
 
697
    }
 
698
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
699
  return 0;
 
700
}
 
701
 
 
702
static const audiodrv_t via8233_audio_driver = {
 
703
  via8233_audio_open,
 
704
  via8233_audio_close,
 
705
  via8233_audio_output_block,
 
706
  via8233_audio_start_input,
 
707
  via8233_audio_ioctl,
 
708
  via8233_audio_prepare_for_input,
 
709
  via8233_audio_prepare_for_output,
 
710
  via8233_audio_reset,
 
711
  NULL,
 
712
  NULL,
 
713
  via8233_audio_reset_input,
 
714
  via8233_audio_reset_output,
 
715
  via8233_audio_trigger,
 
716
  via8233_audio_set_rate,
 
717
  via8233_audio_set_format,
 
718
  via8233_audio_set_channels,
 
719
  NULL,
 
720
  NULL,
 
721
  NULL,                         /* via8233_check_input, */
 
722
  NULL,                         /* via8233_check_output, */
 
723
  via8233_alloc_buffer,
 
724
  via8233_free_buffer,
 
725
  NULL,
 
726
  NULL,
 
727
  via8233_get_buffer_pointer
 
728
};
 
729
 
 
730
static int
 
731
via8233_alloc_engines (via8233_devc * devc)
 
732
{
 
733
  engine_desc *eng;
 
734
  oss_native_word phaddr;
 
735
  int i;
 
736
 
 
737
  for (i = 0; i < MAX_ENGINES; i++)
 
738
    {
 
739
      if (i)
 
740
        {
 
741
          eng = &devc->engines[REC_SGD_NUM];
 
742
          eng->base = devc->base + 0x60;
 
743
        }
 
744
      else
 
745
        {
 
746
          eng = &devc->engines[PLAY_SGD_NUM];
 
747
          eng->base = devc->base + 0x40;
 
748
        }
 
749
 
 
750
      if (eng->sgd == NULL)
 
751
        {
 
752
          eng->sgd =
 
753
            CONTIG_MALLOC (devc->osdev, SGD_ALLOC, MEMLIMIT_32BITS, &phaddr, eng->sgd_dma_handle);
 
754
 
 
755
          if (eng->sgd == NULL)
 
756
            {
 
757
              cmn_err (CE_WARN, "can't allocate SGD table\n");
 
758
              return OSS_ENOSPC;
 
759
            }
 
760
          eng->sgd_phys = phaddr;
 
761
        }
 
762
    }
 
763
  return 0;
 
764
}
 
765
 
 
766
static int
 
767
via8233_init (via8233_devc * devc)
 
768
{
 
769
  int my_mixer, adev, opts;
 
770
  via8233_portc *portc;
 
771
  int i;
 
772
  char tmp_name[50];
 
773
  int first_dev = 0;
 
774
 
 
775
  /* allocate the Scatter Gather Engine buffers */
 
776
  if (via8233_alloc_engines (devc) < 0)
 
777
    {
 
778
      cmn_err (CE_WARN, "Unable to allocate engines\n");
 
779
      return OSS_ENOSPC;
 
780
    }
 
781
 
 
782
  /*
 
783
   * Init mixer
 
784
   */
 
785
  my_mixer =
 
786
    ac97_install (&devc->ac97devc, "VIA823x AC97 Mixer", ac97_read,
 
787
                  ac97_write, devc, devc->osdev);
 
788
 
 
789
  if (my_mixer == -1)
 
790
    {
 
791
      cmn_err (CE_WARN, "AC97 mixer installation failed\n");
 
792
      return 0;                 /* No mixer */
 
793
    }
 
794
 
 
795
  devc->mixer_dev = my_mixer;
 
796
  mixer_devs[my_mixer]->priority = 10;  /* Known motherboard device */
 
797
 
 
798
  /* enable S/PDIF */
 
799
  devc->ac97devc.spdif_slot = SPDIF_SLOT34;
 
800
  ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_ENABLE, SNDCTL_MIX_WRITE, 1);
 
801
 
 
802
  for (i = 0; i < MAX_PORTC; i++)
 
803
    {
 
804
      opts = ADEV_AUTOMODE;
 
805
 
 
806
      if (!ac97_varrate (&devc->ac97devc))
 
807
        {
 
808
          opts |= ADEV_FIXEDRATE;
 
809
        }
 
810
 
 
811
      portc = &devc->portc[i];
 
812
      if (i == 0)
 
813
        {
 
814
          opts |= ADEV_DUPLEX;
 
815
          strcpy (tmp_name, devc->chip_name);
 
816
        }
 
817
      else
 
818
        {
 
819
          opts |= ADEV_DUPLEX | ADEV_SHADOW;
 
820
          strcpy (tmp_name, devc->chip_name);
 
821
        }
 
822
 
 
823
      if ((adev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION,
 
824
                                        devc->osdev,
 
825
                                        devc->osdev,
 
826
                                        tmp_name,
 
827
                                        &via8233_audio_driver,
 
828
                                        sizeof (audiodrv_t),
 
829
                                        opts,
 
830
                                        AFMT_U8 | AFMT_S16_LE | AFMT_AC3,
 
831
                                        devc, -1)) < 0)
 
832
        {
 
833
          adev = -1;
 
834
          return 1;
 
835
        }
 
836
      else
 
837
        {
 
838
          if (i == 0)
 
839
            first_dev = adev;
 
840
          audio_engines[adev]->portc = portc;
 
841
          audio_engines[adev]->rate_source = first_dev;
 
842
          audio_engines[adev]->mixer_dev = my_mixer;
 
843
          audio_engines[adev]->min_rate = 8000;
 
844
          audio_engines[adev]->max_rate = 48000;
 
845
          audio_engines[adev]->caps |= PCM_CAP_FREERATE;
 
846
          audio_engines[adev]->min_channels = 2;
 
847
          audio_engines[adev]->max_channels = 6;
 
848
          if (opts & ADEV_FIXEDRATE)
 
849
            {
 
850
              audio_engines[adev]->fixed_rate = 48000;
 
851
              audio_engines[adev]->min_rate = 48000;
 
852
              audio_engines[adev]->max_rate = 48000;
 
853
            }
 
854
 
 
855
          portc->open_mode = 0;
 
856
          portc->audio_enabled = 0;
 
857
          portc->audiodev = adev;
 
858
#ifdef CONFIG_OSS_VMIX
 
859
          if (i == 0)
 
860
             vmix_attach_audiodev(devc->osdev, adev, -1, 0);
 
861
#endif
 
862
        }
 
863
    }
 
864
 
 
865
  return 1;
 
866
}
 
867
 
 
868
int
 
869
oss_via823x_attach (oss_device_t * osdev)
 
870
{
 
871
  unsigned char pci_irq_line, pci_revision, bTmp /*, pci_latency */ ;
 
872
  unsigned short pci_command, vendor, device;
 
873
  unsigned int pci_ioaddr;
 
874
  via8233_devc *devc;
 
875
 
 
876
  pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor);
 
877
  pci_read_config_word (osdev, PCI_DEVICE_ID, &device);
 
878
 
 
879
  DDB (cmn_err
 
880
       (CE_CONT, "oss_via823x_attach(Vendor %x, device %x)\n", vendor, device));
 
881
  if ((vendor != VIA_VENDOR_ID)
 
882
      || (device != VIA_8233_ID && device != VIA_8233A_ID))
 
883
    {
 
884
 
 
885
      cmn_err (CE_WARN, "Hardware not recognized (vendor=%x, dev=%x)\n",
 
886
               vendor, device);
 
887
      return 0;
 
888
    }
 
889
 
 
890
  pci_read_config_byte (osdev, PCI_REVISION_ID, &pci_revision);
 
891
  pci_read_config_word (osdev, PCI_COMMAND, &pci_command);
 
892
  pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line);
 
893
  pci_read_config_dword (osdev, PCI_BASE_ADDRESS_0, &pci_ioaddr);
 
894
 
 
895
  if (pci_ioaddr == 0)
 
896
    {
 
897
      cmn_err (CE_WARN, "I/O address not assigned by BIOS.\n");
 
898
      return 0;
 
899
    }
 
900
 
 
901
  if (pci_irq_line == 0)
 
902
    {
 
903
      cmn_err (CE_WARN, "IRQ not assigned by BIOS (%d).\n", pci_irq_line);
 
904
      return 0;
 
905
    }
 
906
 
 
907
  if ((devc = PMALLOC (osdev, sizeof (*devc))) == NULL)
 
908
    {
 
909
      cmn_err (CE_WARN, "Out of memory\n");
 
910
      return 0;
 
911
    }
 
912
 
 
913
  devc->osdev = osdev;
 
914
  osdev->devc = devc;
 
915
  devc->open_mode = 0;
 
916
 
 
917
  devc->chip_type = CHIP_8233;
 
918
  devc->chip_name = "VIA VT8233";
 
919
 
 
920
  if (pci_revision == 0x50)
 
921
    devc->chip_name = "VIA VT8235";
 
922
 
 
923
  if (pci_revision == 0x60)
 
924
    devc->chip_name = "VIA VT8237";
 
925
 
 
926
  if ((device == VIA_8233A_ID) ||
 
927
      (device == VIA_8233_ID && pci_revision == 0x40))
 
928
    {
 
929
      devc->chip_type = CHIP_8233A;
 
930
      devc->chip_name = "VIA VT8233A";
 
931
    }
 
932
 
 
933
  pci_write_config_byte (osdev, 0x41, 0xc0);    /*ENAC97 & deassert RESET */
 
934
 
 
935
  oss_udelay (10);
 
936
  pci_read_config_byte (osdev, 0x41, &bTmp);
 
937
  oss_udelay (10);
 
938
  if (devc->chip_type == CHIP_8233A)
 
939
    bTmp |= 0x0C;               /* Enable var rate support */
 
940
  else
 
941
    bTmp |= 0x0f;               /* enable VRA,SB,DX */
 
942
  pci_write_config_byte (osdev, 0x41, bTmp);
 
943
  oss_udelay (10);
 
944
 
 
945
  if (devc->chip_type == CHIP_8233A)
 
946
    {
 
947
      pci_read_config_byte (osdev, 0x49, &bTmp);
 
948
      oss_udelay (10);
 
949
      pci_write_config_byte (osdev, 0x49, 0x0);
 
950
    }
 
951
  else
 
952
    {
 
953
      /* set slot 3,4 as SPDIF on VIA8235 - AC3 passthrough magic! */
 
954
      pci_write_config_byte (osdev, 0x49, 0x1);
 
955
    }
 
956
 
 
957
  devc->base = MAP_PCI_IOADDR (devc->osdev, 0, pci_ioaddr);
 
958
  /* Remove I/O space marker in bit 0. */
 
959
  devc->base &= ~0x3;
 
960
 
 
961
  pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
 
962
  pci_write_config_word (osdev, PCI_COMMAND, pci_command);
 
963
 
 
964
  devc->irq = pci_irq_line;
 
965
 
 
966
  MUTEX_INIT (devc->osdev, devc->mutex, MH_DRV);
 
967
  MUTEX_INIT (devc->osdev, devc->low_mutex, MH_DRV + 1);
 
968
 
 
969
  oss_register_device (osdev, devc->chip_name);
 
970
 
 
971
  if (oss_register_interrupts (devc->osdev, 0, via8233intr, NULL) < 0)
 
972
    {
 
973
      cmn_err (CE_WARN, "Unable to register interrupts\n");
 
974
      return 0;
 
975
    }
 
976
 
 
977
  return via8233_init (devc);   /* Detected */
 
978
}
 
979
 
 
980
int
 
981
oss_via823x_detach (oss_device_t * osdev)
 
982
{
 
983
  via8233_devc *devc = (via8233_devc *) osdev->devc;
 
984
  engine_desc *eng;
 
985
  int i;
 
986
 
 
987
  if (oss_disable_device (devc->osdev) < 0)
 
988
    return 0;
 
989
 
 
990
 
 
991
  /* disable S/PDIF */
 
992
  if (devc->mixer_dev > 0)
 
993
    ac97_spdifout_ctl (devc->mixer_dev, SPDIFOUT_ENABLE, SNDCTL_MIX_WRITE, 0);
 
994
 
 
995
  oss_unregister_interrupts (devc->osdev);
 
996
 
 
997
  for (i = 0; i < MAX_ENGINES; i++)
 
998
    {
 
999
      eng = &devc->engines[i];
 
1000
      if (eng->sgd != NULL)
 
1001
        {
 
1002
          CONTIG_FREE (devc->osdev, eng->sgd, SGD_ALLOC, eng->sgd_dma_handle);
 
1003
          eng->sgd = NULL;
 
1004
        }
 
1005
    }
 
1006
 
 
1007
  MUTEX_CLEANUP (devc->mutex);
 
1008
  MUTEX_CLEANUP (devc->low_mutex);
 
1009
  UNMAP_PCI_IOADDR (devc->osdev, 0);
 
1010
 
 
1011
  oss_unregister_device (devc->osdev);
 
1012
  return 1;
 
1013
}