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

« back to all changes in this revision

Viewing changes to kernel/drv/oss_solo/oss_solo.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 ESS Solo PCI 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_solo_cfg.h"
 
17
#include "oss_pci.h"
 
18
 
 
19
#define ESS_VENDOR_ID   0x125d
 
20
#define ESS_SOLO1       0x1969
 
21
 
 
22
#define DSP_RESET       (devc->sb_base + 0x6)
 
23
#define DSP_READ        (devc->sb_base + 0xA)
 
24
#define DSP_WRITE       (devc->sb_base + 0xC)
 
25
#define DSP_WRSTATUS    (devc->sb_base + 0xC)
 
26
#define DSP_STATUS      (devc->sb_base + 0xE)
 
27
#define DSP_STATUS16    (devc->sb_base + 0xF)
 
28
#define MIXER_ADDR      (devc->sb_base + 0x4)
 
29
#define MIXER_DATA      (devc->sb_base + 0x5)
 
30
#define OPL3_LEFT       (devc->sb_base + 0x0)
 
31
#define OPL3_RIGHT      (devc->sb_base + 0x2)
 
32
#define OPL3_BOTH       (devc->sb_base + 0x8)
 
33
 
 
34
#define DSP_CMD_SPKON           0xD1
 
35
#define DSP_CMD_SPKOFF          0xD3
 
36
 
 
37
#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
 
38
#define SBPRO_MIXER_DEVICES             (SOUND_MASK_SYNTH | SOUND_MASK_PCM | \
 
39
                                         SOUND_MASK_LINE | SOUND_MASK_MIC | \
 
40
                                         SOUND_MASK_CD | SOUND_MASK_VOLUME)
 
41
#define SOLO_RECORDING_DEVICES (SBPRO_RECORDING_DEVICES)
 
42
#define SOLO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER|SOUND_MASK_RECLEV|SOUND_MASK_LINE1)
 
43
 
 
44
#define LEFT_CHN        0
 
45
#define RIGHT_CHN       1
 
46
 
 
47
#define VOC_VOL         0x04
 
48
#define MIC_VOL         0x0A
 
49
#define MIC_MIX         0x0A
 
50
#define RECORD_SRC      0x0C
 
51
#define IN_FILTER       0x0C
 
52
#define OUT_FILTER      0x0E
 
53
#define MASTER_VOL      0x22
 
54
#define FM_VOL          0x26
 
55
#define CD_VOL          0x28
 
56
#define LINE_VOL        0x2E
 
57
#define IRQ_NR          0x80
 
58
#define DMA_NR          0x81
 
59
#define IRQ_STAT        0x82
 
60
#define OPSW            0x3c
 
61
 
 
62
static int default_levels[32] = {
 
63
  0x5a5a,                       /* Master Volume */
 
64
  0x4b4b,                       /* Bass */
 
65
  0x4b4b,                       /* Treble */
 
66
  0x4b4b,                       /* FM */
 
67
  0x4b4b,                       /* PCM */
 
68
  0x4b4b,                       /* PC Speaker */
 
69
  0x4b4b,                       /* Ext Line */
 
70
  0x2020,                       /* Mic */
 
71
  0x4b4b,                       /* CD */
 
72
  0x0000,                       /* Recording monitor */
 
73
  0x4b4b,                       /* SB PCM */
 
74
  0x4b4b,                       /* Recording level */
 
75
  0x4b4b,                       /* Input gain */
 
76
  0x4b4b,                       /* Output gain */
 
77
  0x4040,                       /* Line1 */
 
78
  0x4040,                       /* Line2 */
 
79
  0x1515                        /* Line3 */
 
80
};
 
81
 
 
82
#define MAX_PORTC 2
 
83
 
 
84
typedef struct solo_portc
 
85
{
 
86
  int speed, bits, channels;
 
87
  int open_mode;
 
88
  int audiodev;
 
89
  int trigger_bits;
 
90
  int audio_enabled;
 
91
}
 
92
solo_portc;
 
93
 
 
94
typedef struct solo_devc
 
95
{
 
96
  oss_device_t *osdev;
 
97
  oss_native_word base, ddma_base, sb_base, mpu_base;
 
98
 
 
99
  int mpu_attached, fm_attached;
 
100
  int irq;
 
101
  char *chip_name;
 
102
  oss_mutex_t mutex;
 
103
  oss_mutex_t low_mutex;
 
104
  oss_native_word last_capture_addr;
 
105
  /* Audio parameters */
 
106
  solo_portc portc[MAX_PORTC];
 
107
 
 
108
  /* Mixer parameters */
 
109
  int *levels;
 
110
  int recmask;
 
111
}
 
112
solo_devc;
 
113
 
 
114
 
 
115
static int
 
116
solo_command (solo_devc * devc, unsigned char val)
 
117
{
 
118
  int i;
 
119
 
 
120
  for (i = 0; i < 0x10000; i++)
 
121
    {
 
122
      if ((INB (devc->osdev, DSP_WRSTATUS) & 0x80) == 0)
 
123
        {
 
124
          OUTB (devc->osdev, val, DSP_WRITE);
 
125
          return 1;
 
126
        }
 
127
    }
 
128
 
 
129
  cmn_err (CE_WARN, "Command(%x) Timeout.\n", val);
 
130
  return 0;
 
131
}
 
132
 
 
133
static int
 
134
solo_get_byte (solo_devc * devc)
 
135
{
 
136
  int i;
 
137
 
 
138
  for (i=0; i < 0x10000; i++)
 
139
    if (INB (devc->osdev, DSP_STATUS) & 0x80)
 
140
      {
 
141
        return INB (devc->osdev, DSP_READ);
 
142
      }
 
143
 
 
144
  return 0xffff;
 
145
}
 
146
 
 
147
static int
 
148
ext_read (solo_devc * devc, unsigned char reg)
 
149
{
 
150
 
 
151
  if (!solo_command (devc, 0xc0))       /* Read register command */
 
152
    return OSS_EIO;
 
153
 
 
154
  if (!solo_command (devc, reg))
 
155
    return OSS_EIO;
 
156
 
 
157
  return solo_get_byte (devc);
 
158
}
 
159
 
 
160
static int
 
161
ext_write (solo_devc * devc, unsigned char reg, unsigned char data)
 
162
{
 
163
  if (!solo_command (devc, reg))
 
164
    return 0;
 
165
  return solo_command (devc, data);
 
166
}
 
167
 
 
168
static unsigned int
 
169
solo_getmixer (solo_devc * devc, unsigned int port)
 
170
{
 
171
  unsigned int val;
 
172
  oss_native_word flags;
 
173
 
 
174
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
175
  OUTB (devc->osdev, (unsigned char) (port & 0xff), MIXER_ADDR);
 
176
  oss_udelay (50);
 
177
  val = INB (devc->osdev, MIXER_DATA);
 
178
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
179
  return val;
 
180
}
 
181
 
 
182
static void
 
183
solo_setmixer (solo_devc * devc, unsigned int port, unsigned int value)
 
184
{
 
185
  oss_native_word flags;
 
186
 
 
187
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
188
  OUTB (devc->osdev, (unsigned char) (port & 0xff), MIXER_ADDR);
 
189
  oss_udelay (50);
 
190
  OUTB (devc->osdev, (unsigned char) (value & 0xff), MIXER_DATA);
 
191
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
192
}
 
193
 
 
194
static int
 
195
solo_reset (solo_devc * devc)
 
196
{
 
197
  int loopc;
 
198
 
 
199
  DDB (cmn_err (CE_WARN, "Entered solo_reset()\n"));
 
200
 
 
201
  OUTB (devc->osdev, 3, DSP_RESET);     /* Reset FIFO too */
 
202
  INB (devc->osdev, DSP_RESET); /* Reset FIFO too */
 
203
  OUTB (devc->osdev, 0, DSP_RESET);
 
204
  oss_udelay (10);
 
205
 
 
206
  for (loopc = 0; loopc < 0x10000; loopc++)
 
207
    if (INB (devc->osdev, DSP_STATUS) & 0x80)
 
208
      if (INB (devc->osdev, DSP_READ) != 0xAA)
 
209
        {
 
210
          DDB (cmn_err (CE_WARN, "No response to RESET\n"));
 
211
          return 0;                     /* Sorry */
 
212
        }
 
213
  solo_command (devc, 0xc6);    /* Enable extended mode */
 
214
 
 
215
  ext_write (devc, 0xb9, 3);    /* Demand mode - set to reserve mode */
 
216
  solo_setmixer (devc, 0x71, 0x32); /* 4x sampling + DAC2 asynch */
 
217
 
 
218
  /* enable DMA/IRQ */
 
219
  ext_write (devc, 0xb1, (ext_read (devc, 0xb1) & 0x0F) | 0x50);
 
220
  ext_write (devc, 0xb2, (ext_read (devc, 0xb2) & 0x0F) | 0x50);
 
221
 
 
222
  DDB (cmn_err (CE_WARN, "solo_reset() OK\n"));
 
223
  return 1;
 
224
}
 
225
 
 
226
struct mixer_def
 
227
{
 
228
  unsigned int regno:8;
 
229
  unsigned int bitoffs:4;
 
230
  unsigned int nbits:4;
 
231
};
 
232
 
 
233
typedef struct mixer_def mixer_tab[32][2];
 
234
typedef struct mixer_def mixer_ent;
 
235
 
 
236
#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \
 
237
        {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}}
 
238
 
 
239
static mixer_tab solo_mix = {
 
240
  MIX_ENT (SOUND_MIXER_VOLUME, 0x32, 7, 4, 0x32, 3, 4),
 
241
  MIX_ENT (SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
 
242
  MIX_ENT (SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
 
243
  MIX_ENT (SOUND_MIXER_SYNTH, 0x36, 7, 4, 0x36, 3, 4),
 
244
  MIX_ENT (SOUND_MIXER_PCM, 0x7c, 7, 4, 0x7c, 3, 4),
 
245
  MIX_ENT (SOUND_MIXER_SPEAKER, 0x3c, 2, 3, 0x00, 0, 0),
 
246
  MIX_ENT (SOUND_MIXER_LINE, 0x3e, 7, 4, 0x3e, 3, 4),
 
247
  MIX_ENT (SOUND_MIXER_MIC, 0x1a, 7, 4, 0x1a, 3, 4),
 
248
  MIX_ENT (SOUND_MIXER_CD, 0x38, 7, 4, 0x38, 3, 4),
 
249
  MIX_ENT (SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
 
250
  MIX_ENT (SOUND_MIXER_ALTPCM, 0x7c, 7, 4, 0x7c, 3, 4),
 
251
  MIX_ENT (SOUND_MIXER_RECLEV, 0xb4, 7, 4, 0xb4, 3, 4),
 
252
  MIX_ENT (SOUND_MIXER_IGAIN, 0x68, 7, 4, 0x68, 3, 4),
 
253
  MIX_ENT (SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0),
 
254
  MIX_ENT (SOUND_MIXER_LINE1, 0x6d, 7, 4, 0x6d, 3, 4),
 
255
  MIX_ENT (SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4),
 
256
  MIX_ENT (SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0)
 
257
};
 
258
 
 
259
/*ARGSUSED*/
 
260
static void
 
261
change_bits (solo_devc * devc, unsigned char *regval, int dev, int chn,
 
262
             int newval)
 
263
{
 
264
  unsigned char mask;
 
265
  int shift;
 
266
 
 
267
  mask = (1 << solo_mix[dev][chn].nbits) - 1;
 
268
  newval = (int) ((newval * mask) + 50) / 100;  /* Scale */
 
269
 
 
270
  shift = solo_mix[dev][chn].bitoffs - solo_mix[dev][LEFT_CHN].nbits + 1;
 
271
 
 
272
  *regval &= ~(mask << shift);  /* Mask out previous value */
 
273
  *regval |= (newval & mask) << shift;  /* Set the new value */
 
274
}
 
275
 
 
276
#if 0
 
277
static int
 
278
ess_set_reclev (solo_devc * devc, int dev, int left, int right)
 
279
{
 
280
  unsigned char b;
 
281
 
 
282
  b = (((15 * right) / 100) << 4) | (((15 * left) / 100));
 
283
 
 
284
  ext_write (devc, 0xb4, b);    /* Change input volume control */
 
285
  devc->levels[dev] = left | (right << 8);
 
286
  return left | (right << 8);
 
287
}
 
288
 
 
289
static int
 
290
ess_set_altpcm (solo_devc * devc, int dev, int left, int right)
 
291
{
 
292
  unsigned char b;
 
293
 
 
294
  b = (((15 * right) / 100) << 4) | (((15 * left) / 100));
 
295
  solo_setmixer (devc, 0x7C, b);        /* Change dac2 volume control */
 
296
  devc->levels[dev] = left | (right << 8);
 
297
  return left | (right << 8);
 
298
}
 
299
#endif
 
300
 
 
301
static int set_recmask (solo_devc * devc, int mask);
 
302
 
 
303
static int
 
304
solo_mixer_set (solo_devc * devc, int dev, int value)
 
305
{
 
306
  int left = value & 0x000000ff;
 
307
  int right = (value & 0x0000ff00) >> 8;
 
308
 
 
309
  int regoffs;
 
310
  unsigned char val;
 
311
 
 
312
  if (left > 100)
 
313
    left = 100;
 
314
  if (right > 100)
 
315
    right = 100;
 
316
 
 
317
#if 0
 
318
  if (dev == SOUND_MIXER_RECLEV)
 
319
    return ess_set_reclev (devc, dev, left, right);
 
320
  if (dev == SOUND_MIXER_ALTPCM)
 
321
    return ess_set_altpcm (devc, dev, left, right);
 
322
#endif
 
323
 
 
324
  if (dev > 31)
 
325
    return OSS_EINVAL;
 
326
 
 
327
  if (!(SOLO_MIXER_DEVICES & (1 << dev)))       /*
 
328
                                                 * Not supported
 
329
                                                 */
 
330
    return OSS_EINVAL;
 
331
 
 
332
  regoffs = solo_mix[dev][LEFT_CHN].regno;
 
333
 
 
334
  if (regoffs == 0)
 
335
    return OSS_EINVAL;
 
336
 
 
337
  val = solo_getmixer (devc, regoffs);
 
338
  change_bits (devc, &val, dev, LEFT_CHN, left);
 
339
 
 
340
  devc->levels[dev] = left | (left << 8);
 
341
 
 
342
  if (solo_mix[dev][RIGHT_CHN].regno != regoffs)        /*
 
343
                                                         * Change register
 
344
                                                         */
 
345
    {
 
346
      solo_setmixer (devc, regoffs, val);       /*
 
347
                                                 * Save the old one
 
348
                                                 */
 
349
      regoffs = solo_mix[dev][RIGHT_CHN].regno;
 
350
 
 
351
      if (regoffs == 0)
 
352
        return left | (left << 8);      /*
 
353
                                         * Just left channel present
 
354
                                         */
 
355
 
 
356
      val = solo_getmixer (devc, regoffs);      /*
 
357
                                                 * Read the new one
 
358
                                                 */
 
359
    }
 
360
 
 
361
  change_bits (devc, &val, dev, RIGHT_CHN, right);
 
362
 
 
363
  solo_setmixer (devc, regoffs, val);
 
364
 
 
365
  devc->levels[dev] = left | (right << 8);
 
366
  return left | (right << 8);
 
367
}
 
368
 
 
369
/*ARGSUSED*/
 
370
static int
 
371
solo_mixer_ioctl (int dev, int audiodev, unsigned int cmd, ioctl_arg arg)
 
372
{
 
373
  solo_devc *devc = mixer_devs[dev]->devc;
 
374
  int val;
 
375
 
 
376
  if (cmd == SOUND_MIXER_PRIVATE1)
 
377
    {
 
378
      val = *arg;
 
379
      if (val != 0 && val != 1)
 
380
        return (OSS_EINVAL);
 
381
 
 
382
      if (val)
 
383
        {
 
384
          cmn_err (CE_WARN, "turning on 26db mic boost\n");
 
385
          ext_write (devc, 0xa9, ext_read (devc, 0xa9) | 0xC);
 
386
        }
 
387
      else
 
388
        {
 
389
          cmn_err (CE_WARN, "turning off 26db mic boost\n");
 
390
          ext_write (devc, 0xa9, ext_read (devc, 0xa9) & ~0x4);
 
391
        }
 
392
      return *arg = val;
 
393
    }
 
394
 
 
395
 
 
396
  if (((cmd >> 8) & 0xff) == 'M')
 
397
    {
 
398
      if (IOC_IS_OUTPUT (cmd))
 
399
        switch (cmd & 0xff)
 
400
          {
 
401
          case SOUND_MIXER_RECSRC:
 
402
            val = *arg;
 
403
            return *arg = set_recmask (devc, val);
 
404
            break;
 
405
 
 
406
          default:
 
407
 
 
408
            val = *arg;
 
409
            return *arg = solo_mixer_set (devc, cmd & 0xff, val);
 
410
          }
 
411
      else
 
412
        switch (cmd & 0xff)
 
413
          {
 
414
 
 
415
          case SOUND_MIXER_RECSRC:
 
416
            return *arg = devc->recmask;
 
417
            break;
 
418
 
 
419
          case SOUND_MIXER_DEVMASK:
 
420
            return *arg = SOLO_MIXER_DEVICES;
 
421
            break;
 
422
 
 
423
          case SOUND_MIXER_STEREODEVS:
 
424
            return *arg = SOLO_MIXER_DEVICES &
 
425
              ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
 
426
            break;
 
427
 
 
428
          case SOUND_MIXER_RECMASK:
 
429
            return *arg = SOLO_RECORDING_DEVICES;
 
430
            break;
 
431
 
 
432
          case SOUND_MIXER_CAPS:
 
433
            return *arg = SOUND_CAP_EXCL_INPUT;
 
434
            break;
 
435
 
 
436
          default:
 
437
            return *arg = devc->levels[cmd & 0x1f];
 
438
          }
 
439
    }
 
440
  else
 
441
    return OSS_EINVAL;
 
442
}
 
443
 
 
444
static void
 
445
set_recsrc (solo_devc * devc, int src)
 
446
{
 
447
  solo_setmixer (devc, RECORD_SRC,
 
448
                 (solo_getmixer (devc, RECORD_SRC) & ~7) | (src & 0x7));
 
449
}
 
450
 
 
451
static int
 
452
set_recmask (solo_devc * devc, int mask)
 
453
{
 
454
  int devmask = mask & SOLO_RECORDING_DEVICES;
 
455
 
 
456
  if (devmask != SOUND_MASK_MIC &&
 
457
      devmask != SOUND_MASK_LINE && devmask != SOUND_MASK_CD)
 
458
    {                           /*
 
459
                                 * More than one devices selected. 
 
460
                                 * Drop the previous selection
 
461
                                 */
 
462
      devmask &= ~devc->recmask;
 
463
    }
 
464
 
 
465
  if (devmask != SOUND_MASK_MIC &&
 
466
      devmask != SOUND_MASK_LINE && devmask != SOUND_MASK_CD)
 
467
    {                           /*
 
468
                                 * More than one devices selected.
 
469
                                 * Default to mic
 
470
                                 */
 
471
      devmask = SOUND_MASK_MIC;
 
472
    }
 
473
 
 
474
 
 
475
  if (devmask ^ devc->recmask)  /*
 
476
                                 * Input source changed
 
477
                                 */
 
478
    {
 
479
      switch (devmask)
 
480
        {
 
481
 
 
482
        case SOUND_MASK_MIC:
 
483
          set_recsrc (devc, 0);
 
484
          break;
 
485
 
 
486
        case SOUND_MASK_LINE:
 
487
          set_recsrc (devc, 6);
 
488
          break;
 
489
 
 
490
        case SOUND_MASK_CD:
 
491
          set_recsrc (devc, 2);
 
492
          break;
 
493
 
 
494
        default:
 
495
          set_recsrc (devc, 0);
 
496
        }
 
497
    }
 
498
 
 
499
  devc->recmask = devmask;
 
500
  return devc->recmask;
 
501
}
 
502
 
 
503
static void
 
504
solo_mixer_reset (solo_devc * devc)
 
505
{
 
506
  char name[32];
 
507
  int i;
 
508
 
 
509
  sprintf (name, "SOLO");
 
510
 
 
511
  devc->levels = load_mixer_volumes (name, default_levels, 1);
 
512
  devc->recmask = 0;
 
513
 
 
514
  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 
515
    solo_mixer_set (devc, i, devc->levels[i]);
 
516
 
 
517
  set_recmask (devc, SOUND_MASK_MIC);
 
518
}
 
519
 
 
520
static mixer_driver_t solo_mixer_driver = {
 
521
  solo_mixer_ioctl
 
522
};
 
523
 
 
524
static int
 
525
solointr (oss_device_t * osdev)
 
526
{
 
527
  solo_devc *devc = (solo_devc *) osdev->devc;
 
528
  int status;
 
529
  int serviced = 0;
 
530
  int i;
 
531
  oss_native_word flags;
 
532
 
 
533
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
534
  status = INB (devc->osdev, devc->base + 7);
 
535
 
 
536
  for (i = 0; i < MAX_PORTC; i++)
 
537
    {
 
538
      if (status & 0x10)        /* ESS Native Mode */
 
539
        {
 
540
          int instat;
 
541
          solo_portc *portc = &devc->portc[i];
 
542
          serviced = 1;
 
543
 
 
544
          instat = INB (devc->osdev, DSP_STATUS);       /* Ack the interrupt */
 
545
          if (portc->trigger_bits & PCM_ENABLE_INPUT)
 
546
            oss_audio_inputintr (portc->audiodev, 1);
 
547
        }
 
548
 
 
549
      if (status & 0x20)        /* ESS DAC2 Mode */
 
550
        {
 
551
          solo_portc *portc = &devc->portc[i];
 
552
          serviced = 1;
 
553
 
 
554
          if (portc->trigger_bits & PCM_ENABLE_OUTPUT)
 
555
            oss_audio_outputintr (portc->audiodev, 1);
 
556
          solo_setmixer (devc, 0x7A, solo_getmixer (devc, 0x7A) & 0x47);
 
557
        }
 
558
    }
 
559
 
 
560
  if (status & 0x80)            /* MPU interrupt */
 
561
    {
 
562
      serviced = 1;
 
563
      /* uart401intr (INT_HANDLER_CALL (devc->irq)); *//* UART401 interrupt */
 
564
    }
 
565
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
566
 
 
567
  return serviced;
 
568
}
 
569
 
 
570
static int
 
571
solo_audio_set_rate (int dev, int arg)
 
572
{
 
573
  solo_portc *portc = audio_engines[dev]->portc;
 
574
 
 
575
  if (arg == 0)
 
576
    return portc->speed;
 
577
 
 
578
  if (arg > 48000)
 
579
    arg = 48000;
 
580
  if (arg < 8000)
 
581
    arg = 8000;
 
582
  portc->speed = arg;
 
583
  return portc->speed;
 
584
}
 
585
 
 
586
static short
 
587
solo_audio_set_channels (int dev, short arg)
 
588
{
 
589
  solo_portc *portc = audio_engines[dev]->portc;
 
590
 
 
591
  if ((arg != 1) && (arg != 2))
 
592
    return portc->channels;
 
593
  portc->channels = arg;
 
594
 
 
595
  return portc->channels;
 
596
}
 
597
 
 
598
static unsigned int
 
599
solo_audio_set_format (int dev, unsigned int arg)
 
600
{
 
601
  solo_portc *portc = audio_engines[dev]->portc;
 
602
 
 
603
  if (arg == 0)
 
604
    return portc->bits;
 
605
 
 
606
  if (!(arg & (AFMT_U8 | AFMT_S16_LE)))
 
607
    return portc->bits;
 
608
  portc->bits = arg;
 
609
 
 
610
  return portc->bits;
 
611
}
 
612
 
 
613
/*ARGSUSED*/
 
614
static int
 
615
solo_audio_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
 
616
{
 
617
  return OSS_EINVAL;
 
618
}
 
619
 
 
620
static void solo_audio_trigger (int dev, int state);
 
621
 
 
622
static void
 
623
solo_audio_reset (int dev)
 
624
{
 
625
  solo_audio_trigger (dev, 0);
 
626
}
 
627
 
 
628
static void
 
629
solo_audio_reset_input (int dev)
 
630
{
 
631
  solo_portc *portc = audio_engines[dev]->portc;
 
632
  solo_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_INPUT);
 
633
}
 
634
 
 
635
static void
 
636
solo_audio_reset_output (int dev)
 
637
{
 
638
  solo_portc *portc = audio_engines[dev]->portc;
 
639
  solo_audio_trigger (dev, portc->trigger_bits & ~PCM_ENABLE_OUTPUT);
 
640
}
 
641
 
 
642
/*ARGSUSED*/
 
643
static int
 
644
solo_audio_open (int dev, int mode, int open_flags)
 
645
{
 
646
  oss_native_word flags;
 
647
  solo_portc *portc = audio_engines[dev]->portc;
 
648
  solo_devc *devc = audio_engines[dev]->devc;
 
649
 
 
650
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
651
  if (portc->open_mode)
 
652
    {
 
653
      MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
654
      return OSS_EBUSY;
 
655
    }
 
656
  portc->open_mode = mode;
 
657
  portc->audio_enabled = ~mode;
 
658
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
659
 
 
660
  return 0;
 
661
}
 
662
 
 
663
static void
 
664
solo_audio_close (int dev, int mode)
 
665
{
 
666
  solo_portc *portc = audio_engines[dev]->portc;
 
667
 
 
668
  solo_audio_reset (dev);
 
669
  portc->open_mode = 0;
 
670
  portc->audio_enabled &= ~mode;
 
671
}
 
672
 
 
673
/*ARGSUSED*/
 
674
static void
 
675
solo_audio_output_block (int dev, oss_native_word buf, int count,
 
676
                         int fragsize, int intrflag)
 
677
{
 
678
  solo_portc *portc = audio_engines[dev]->portc;
 
679
 
 
680
  portc->audio_enabled |= PCM_ENABLE_OUTPUT;
 
681
  portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
682
 
 
683
}
 
684
 
 
685
/*ARGSUSED*/
 
686
static void
 
687
solo_audio_start_input (int dev, oss_native_word buf, int count,
 
688
                        int fragsize, int intrflag)
 
689
{
 
690
  solo_portc *portc = audio_engines[dev]->portc;
 
691
 
 
692
  portc->audio_enabled |= PCM_ENABLE_INPUT;
 
693
  portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
694
}
 
695
 
 
696
static void
 
697
solo_audio_trigger (int dev, int state)
 
698
{
 
699
  oss_native_word flags;
 
700
  solo_portc *portc = audio_engines[dev]->portc;
 
701
  solo_devc *devc = audio_engines[dev]->devc;
 
702
 
 
703
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
704
  if (portc->open_mode & OPEN_WRITE)
 
705
    {
 
706
      if (state & PCM_ENABLE_OUTPUT)
 
707
        {
 
708
          if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) &&
 
709
              !(portc->trigger_bits & PCM_ENABLE_OUTPUT))
 
710
            {
 
711
              solo_setmixer (devc, 0x78, 0x92); /* stablilze fifos */
 
712
              oss_udelay(100);
 
713
              solo_setmixer (devc, 0x78, 0x93); /* Go */
 
714
              OUTB (devc->osdev, 0x0A, devc->base + 6);     /*unmask dac2 intr */
 
715
              portc->trigger_bits |= PCM_ENABLE_OUTPUT;
 
716
            }
 
717
        }
 
718
      else
 
719
        {
 
720
          if ((portc->audio_enabled & PCM_ENABLE_OUTPUT) &&
 
721
              (portc->trigger_bits & PCM_ENABLE_OUTPUT))
 
722
            {
 
723
              portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
724
              portc->audio_enabled &= ~PCM_ENABLE_OUTPUT;
 
725
              solo_setmixer (devc, 0x78, 0);    /* stop the audio dac2 dma */
 
726
            }
 
727
        }
 
728
    }
 
729
 
 
730
  if (portc->open_mode & OPEN_READ)
 
731
    {
 
732
      if (state & PCM_ENABLE_INPUT)
 
733
        {
 
734
          if ((portc->audio_enabled & PCM_ENABLE_INPUT) &&
 
735
              !(portc->trigger_bits & PCM_ENABLE_INPUT))
 
736
            {
 
737
              ext_write (devc, 0xb8, 0x0f);     /* Go */
 
738
              OUTB (devc->osdev, 0x00, devc->ddma_base + 0x0f); /*start dma*/
 
739
              portc->trigger_bits |= PCM_ENABLE_INPUT;
 
740
            }
 
741
        }
 
742
      else
 
743
        {
 
744
          if ((portc->audio_enabled & PCM_ENABLE_INPUT) &&
 
745
              (portc->trigger_bits & PCM_ENABLE_INPUT))
 
746
            {
 
747
              portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
748
              portc->audio_enabled &= ~PCM_ENABLE_INPUT;
 
749
              ext_write (devc, 0xb8, 0x00);     /* stop */
 
750
            }
 
751
        }
 
752
    }
 
753
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
754
}
 
755
 
 
756
static void
 
757
ext_speed (int dev, int direction)
 
758
{
 
759
  solo_devc *devc = audio_engines[dev]->devc;
 
760
  solo_portc *portc = audio_engines[dev]->portc;
 
761
  int divider, div, filter;
 
762
  unsigned int rate;
 
763
  int speed, s0, s1, use0;
 
764
  int dif0, dif1;
 
765
  unsigned char t0, t1;
 
766
 
 
767
  /* rate = source / (256 - divisor) */
 
768
  /* divisor = 256 - (source / rate) */
 
769
  speed = portc->speed;
 
770
 
 
771
  t0 = 128 - (793800 / speed);
 
772
  s0 = 793800 / (128 - t0);
 
773
 
 
774
  t1 = 128 - (768000 / speed);
 
775
  s1 = 768000 / (128 - t1);
 
776
  t1 |= 0x80;
 
777
 
 
778
  dif0 = speed - s0;
 
779
  if (dif0 < 0)
 
780
    dif0 *= -1;
 
781
  dif1 = speed - s1;
 
782
  if (dif1 < 0)
 
783
    dif1 *= -1;
 
784
 
 
785
  use0 = (dif0 < dif1) ? 1 : 0;
 
786
 
 
787
  if (use0)
 
788
    {
 
789
      rate = s0;
 
790
      div = t0;
 
791
    }
 
792
  else
 
793
    {
 
794
      rate = s1;
 
795
      div = t1;
 
796
    }
 
797
  portc->speed = rate;
 
798
/*
 
799
 * Set filter divider register
 
800
 */
 
801
  filter = (rate * 8 * 82) / 20;        /* 80% of the rate */
 
802
  divider = 256 - 7160000 / (filter);
 
803
  if (direction)
 
804
    {
 
805
      ext_write (devc, 0xa1, div);
 
806
      ext_write (devc, 0xa2, divider);
 
807
    }
 
808
  else
 
809
    {
 
810
      solo_setmixer (devc, 0x70, div);
 
811
      solo_setmixer (devc, 0x72, divider);
 
812
    }
 
813
}
 
814
 
 
815
/*ARGSUSED*/
 
816
static int
 
817
solo_audio_prepare_for_input (int dev, int bsize, int bcount)
 
818
{
 
819
  solo_devc *devc = audio_engines[dev]->devc;
 
820
  solo_portc *portc = audio_engines[dev]->portc;
 
821
  oss_native_word flags;
 
822
  unsigned int left, right, reclev;
 
823
  dmap_t *dmap = audio_engines[dev]->dmap_in;
 
824
  int c;
 
825
 
 
826
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
827
  OUTB (devc->osdev, 2, DSP_RESET);     /* Reset FIFO too */
 
828
  INB (devc->osdev, DSP_RESET); /* Reset FIFO too */
 
829
  OUTB (devc->osdev, 0, DSP_RESET);
 
830
  oss_udelay (10);
 
831
 
 
832
 
 
833
  ext_speed (dev, 1);
 
834
 
 
835
  ext_write (devc, 0xa8, (ext_read (devc, 0xa8) & ~0x3) | (3 - portc->channels));       /* Mono/stereo */
 
836
 
 
837
  solo_command (devc, DSP_CMD_SPKOFF);
 
838
 
 
839
  if (portc->channels == 1)
 
840
    {
 
841
      if (portc->bits == AFMT_U8)
 
842
        {                       /* 8 bit mono */
 
843
          ext_write (devc, 0xb7, 0x51);
 
844
          ext_write (devc, 0xb7, 0xd0);
 
845
        }
 
846
      else
 
847
        {                       /* 16 bit mono */
 
848
          ext_write (devc, 0xb7, 0x71);
 
849
          ext_write (devc, 0xb7, 0xf4);
 
850
        }
 
851
    }
 
852
  else
 
853
    {                           /* Stereo */
 
854
      if (portc->bits == AFMT_U8)
 
855
        {                       /* 8 bit stereo */
 
856
          ext_write (devc, 0xb7, 0x51);
 
857
          ext_write (devc, 0xb7, 0x98);
 
858
        }
 
859
      else
 
860
        {                       /* 16 bit stereo */
 
861
          ext_write (devc, 0xb7, 0x71);
 
862
          ext_write (devc, 0xb7, 0xbc);
 
863
        }
 
864
    }
 
865
 
 
866
  /* 
 
867
   * reset the 0xb4 register to the stored value of RECLEV - for some 
 
868
   * reason it gets reset when you enter ESS Extension mode.
 
869
   */
 
870
  left = devc->levels[SOUND_MIXER_RECLEV] & 0xff;
 
871
  right = (devc->levels[SOUND_MIXER_RECLEV] >> 8) & 0xff;
 
872
  reclev = (((15 * right) / 100) << 4) | (((15 * left) / 100));
 
873
  ext_write (devc, 0xb4, reclev);
 
874
 
 
875
  OUTB (devc->osdev, 0xc4, devc->ddma_base + 0x08);
 
876
  OUTB (devc->osdev, 0xff, devc->ddma_base + 0x0d);   /* clear DMA */
 
877
  OUTB (devc->osdev, 0x01, devc->ddma_base + 0x0f);  /* stop DMA */
 
878
  OUTB (devc->osdev, 0x14, devc->ddma_base + 0x0b);  /*Demand/Single Mode */
 
879
 
 
880
  OUTL (devc->osdev, dmap->dmabuf_phys, devc->ddma_base + 0x00);
 
881
  OUTW (devc->osdev, dmap->bytes_in_use, devc->ddma_base + 0x04);
 
882
 
 
883
  c = -(dmap->fragment_size);
 
884
  /* Reload DMA Count */
 
885
  ext_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
 
886
  ext_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
 
887
 
 
888
  portc->audio_enabled &= ~PCM_ENABLE_INPUT;
 
889
  portc->trigger_bits &= ~PCM_ENABLE_INPUT;
 
890
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
891
  return 0;
 
892
}
 
893
 
 
894
/*ARGSUSED*/
 
895
static int
 
896
solo_audio_prepare_for_output (int dev, int bsize, int bcount)
 
897
{
 
898
  solo_devc *devc = audio_engines[dev]->devc;
 
899
  solo_portc *portc = audio_engines[dev]->portc;
 
900
  oss_native_word flags;
 
901
  dmap_t *dmap = audio_engines[dev]->dmap_out;
 
902
  int c;
 
903
 
 
904
 
 
905
  MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
 
906
  OUTB (devc->osdev, 2, DSP_RESET);     /* Reset FIFO too */
 
907
  INB (devc->osdev, DSP_RESET); 
 
908
  OUTB (devc->osdev, 0, DSP_RESET);
 
909
  ext_speed (dev, 0);
 
910
  if (portc->channels == 1)
 
911
    {
 
912
      if (portc->bits == AFMT_U8)
 
913
        solo_setmixer (devc, 0x7A, 0x40 | 0x00);        /*8bit mono unsigned */
 
914
      else
 
915
        solo_setmixer (devc, 0x7A, 0x40 | 0x05);        /*16bit mono signed */
 
916
    }
 
917
  else
 
918
    {
 
919
      if (portc->bits == AFMT_U8)
 
920
        solo_setmixer (devc, 0x7A, 0x40 | 0x02);        /*8bit stereo unsigned */
 
921
      else
 
922
        solo_setmixer (devc, 0x7A, 0x40 | 0x07);        /*16bit stereo signed */
 
923
    }
 
924
 
 
925
  OUTL (devc->osdev, dmap->dmabuf_phys, devc->base + 0);
 
926
  OUTW (devc->osdev, dmap->bytes_in_use, devc->base + 4);
 
927
 
 
928
  OUTB (devc->osdev, 0x0, devc->base + 6);      /* disable the DMA mask */
 
929
 
 
930
  c = -(dmap->fragment_size>>1);
 
931
  solo_setmixer (devc, 0x74, (unsigned char) ((unsigned short) c & 0xff));
 
932
  solo_setmixer (devc, 0x76, (unsigned char) (((unsigned short) c >> 8) & 0xff));
 
933
  portc->audio_enabled &= ~PCM_ENABLE_OUTPUT;
 
934
  portc->trigger_bits &= ~PCM_ENABLE_OUTPUT;
 
935
  MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
 
936
  return 0;
 
937
}
 
938
 
 
939
static int
 
940
solo_get_buffer_pointer (int dev, dmap_t * dmap, int direction)
 
941
{
 
942
  solo_devc *devc = audio_engines[dev]->devc;
 
943
  oss_native_word flags;
 
944
  oss_native_word ptr=0;
 
945
 
 
946
  MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
 
947
  if (direction == PCM_ENABLE_OUTPUT)
 
948
  {
 
949
      ptr = dmap->bytes_in_use - INW(devc->osdev, devc->base + 4);
 
950
  }
 
951
 
 
952
  if (direction == PCM_ENABLE_INPUT)
 
953
  {
 
954
      int count;
 
955
      unsigned int diff;
 
956
 
 
957
      ptr = INL(devc->osdev, devc->ddma_base + 0x00);
 
958
      count = INL(devc->osdev, devc->ddma_base + 0x04);
 
959
 
 
960
      diff = dmap->dmabuf_phys + dmap->bytes_in_use - ptr - count;
 
961
 
 
962
      if (ptr < dmap->dmabuf_phys || 
 
963
          ptr >= dmap->dmabuf_phys + dmap->bytes_in_use)
 
964
 
 
965
           ptr = devc->last_capture_addr;            /* use prev value */
 
966
      else
 
967
           devc->last_capture_addr = ptr;            /* save it */
 
968
 
 
969
      ptr -= dmap->dmabuf_phys;
 
970
  }
 
971
 
 
972
  MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
 
973
  return ptr;
 
974
}
 
975
 
 
976
 
 
977
static audiodrv_t solo_audio_driver = {
 
978
  solo_audio_open,
 
979
  solo_audio_close,
 
980
  solo_audio_output_block,
 
981
  solo_audio_start_input,
 
982
  solo_audio_ioctl,
 
983
  solo_audio_prepare_for_input,
 
984
  solo_audio_prepare_for_output,
 
985
  solo_audio_reset,
 
986
  NULL,
 
987
  NULL,
 
988
  solo_audio_reset_input,
 
989
  solo_audio_reset_output,
 
990
  solo_audio_trigger,
 
991
  solo_audio_set_rate,
 
992
  solo_audio_set_format,
 
993
  solo_audio_set_channels,
 
994
  NULL,
 
995
  NULL,
 
996
  NULL,
 
997
  NULL,
 
998
  NULL,                         /* solo_alloc_buffer, */
 
999
  NULL,                         /* solo_free_buffer, */
 
1000
  NULL,
 
1001
  NULL,
 
1002
  solo_get_buffer_pointer 
 
1003
};
 
1004
 
 
1005
static int
 
1006
init_solo (solo_devc * devc)
 
1007
{
 
1008
  int my_mixer;
 
1009
  int i, adev;
 
1010
  int first_dev = 0;
 
1011
 
 
1012
  devc->mpu_attached = devc->fm_attached = 0;
 
1013
 
 
1014
/*
 
1015
 * Initialize and attach the legacy devices
 
1016
 */
 
1017
 
 
1018
  if (!solo_reset (devc))
 
1019
    {
 
1020
      cmn_err (CE_WARN, "Reset command failed\n");
 
1021
      return 0;
 
1022
    }
 
1023
 
 
1024
/* setup mixer regs */
 
1025
  solo_setmixer (devc, 0x7d, 0x0c);
 
1026
  OUTB (devc->osdev, 0xf0, devc->base + 7); 
 
1027
  OUTB (devc->osdev, 0x00, devc->ddma_base + 0x0f);
 
1028
 
 
1029
  if ((my_mixer = oss_install_mixer (OSS_MIXER_DRIVER_VERSION,
 
1030
                                     devc->osdev,
 
1031
                                     devc->osdev,
 
1032
                                     "ESS Solo",
 
1033
                                     &solo_mixer_driver,
 
1034
                                     sizeof (mixer_driver_t), devc)) < 0)
 
1035
    {
 
1036
      return 0;
 
1037
    }
 
1038
  solo_mixer_reset (devc);
 
1039
 
 
1040
  for (i = 0; i < MAX_PORTC; i++)
 
1041
    {
 
1042
      char tmp_name[100];
 
1043
      solo_portc *portc = &devc->portc[i];
 
1044
      int caps = ADEV_AUTOMODE;
 
1045
      strcpy (tmp_name, devc->chip_name);
 
1046
 
 
1047
      if (i == 0)
 
1048
        {
 
1049
          strcpy (tmp_name, devc->chip_name);
 
1050
          caps |= ADEV_DUPLEX;
 
1051
        }
 
1052
      else
 
1053
        {
 
1054
          caps |= ADEV_DUPLEX | ADEV_SHADOW;
 
1055
        }
 
1056
 
 
1057
      if ((adev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION,
 
1058
                                        devc->osdev,
 
1059
                                        devc->osdev,
 
1060
                                        tmp_name,
 
1061
                                        &solo_audio_driver,
 
1062
                                        sizeof (audiodrv_t),
 
1063
                                        caps,
 
1064
                                        AFMT_U8 | AFMT_S16_LE, devc, -1)) < 0)
 
1065
        {
 
1066
          adev = -1;
 
1067
          return 0;
 
1068
        }
 
1069
      else
 
1070
        {
 
1071
          if (i == 0)
 
1072
            first_dev = adev;
 
1073
          audio_engines[adev]->portc = portc;
 
1074
          audio_engines[adev]->rate_source = first_dev;
 
1075
          audio_engines[adev]->mixer_dev = my_mixer;
 
1076
          audio_engines[adev]->min_rate = 8000;
 
1077
          audio_engines[adev]->max_rate = 48000;
 
1078
          audio_engines[adev]->dmabuf_maxaddr = MEMLIMIT_ISA;
 
1079
          audio_engines[adev]->dmabuf_alloc_flags |= DMABUF_SIZE_16BITS;
 
1080
          audio_engines[adev]->caps |= PCM_CAP_FREERATE;
 
1081
          portc->open_mode = 0;
 
1082
          portc->audiodev = adev;
 
1083
          portc->audio_enabled = 0;
 
1084
#ifdef CONFIG_OSS_VMIX
 
1085
          if (i == 0)
 
1086
             vmix_attach_audiodev(devc->osdev, adev, -1, 0);
 
1087
#endif
 
1088
        }
 
1089
    }
 
1090
  return 1;
 
1091
}
 
1092
 
 
1093
int
 
1094
oss_solo_attach (oss_device_t * osdev)
 
1095
{
 
1096
 
 
1097
  unsigned char pci_irq_line, pci_revision;
 
1098
  unsigned short pci_command, vendor, device;
 
1099
  unsigned int pci_ioaddr0, pci_ioaddr1, pci_ioaddr2, pci_ioaddr3;
 
1100
  solo_devc *devc;
 
1101
 
 
1102
  DDB (cmn_err (CE_WARN, "Entered ESS Solo probe routine\n"));
 
1103
 
 
1104
  pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor);
 
1105
  pci_read_config_word (osdev, PCI_DEVICE_ID, &device);
 
1106
 
 
1107
  if (vendor != ESS_VENDOR_ID || device != ESS_SOLO1)
 
1108
    return 0;
 
1109
 
 
1110
  pci_read_config_byte (osdev, PCI_REVISION_ID, &pci_revision);
 
1111
  pci_read_config_word (osdev, PCI_COMMAND, &pci_command);
 
1112
  pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line);
 
1113
  pci_read_config_dword (osdev, PCI_BASE_ADDRESS_0, &pci_ioaddr0);
 
1114
  pci_read_config_dword (osdev, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
 
1115
  pci_read_config_dword (osdev, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
 
1116
  pci_read_config_dword (osdev, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
 
1117
 
 
1118
  if (pci_ioaddr0 == 0)
 
1119
    {
 
1120
      cmn_err (CE_WARN, "I/O address not assigned by BIOS.\n");
 
1121
      return 0;
 
1122
    }
 
1123
 
 
1124
  if (pci_irq_line == 0)
 
1125
    {
 
1126
      cmn_err (CE_WARN, "IRQ not assigned by BIOS (%d).\n", pci_irq_line);
 
1127
      return 0;
 
1128
    }
 
1129
 
 
1130
  if ((devc = PMALLOC (osdev, sizeof (*devc))) == NULL)
 
1131
    {
 
1132
      cmn_err (CE_WARN, "Out of memory\n");
 
1133
      return 0;
 
1134
    }
 
1135
 
 
1136
  devc->osdev = osdev;
 
1137
  osdev->devc = devc;
 
1138
  devc->irq = pci_irq_line;
 
1139
  devc->chip_name = "ESS Solo-1";
 
1140
 
 
1141
  devc->base = MAP_PCI_IOADDR (devc->osdev, 0, pci_ioaddr0);
 
1142
  /* Remove I/O space marker in bit 0. */
 
1143
  devc->base &= ~0x3;
 
1144
 
 
1145
  pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
 
1146
  pci_write_config_word (osdev, PCI_COMMAND, pci_command);
 
1147
 
 
1148
  MUTEX_INIT (devc->osdev, devc->mutex, MH_DRV);
 
1149
  MUTEX_INIT (devc->osdev, devc->low_mutex, MH_DRV + 1);
 
1150
 
 
1151
  oss_register_device (osdev, devc->chip_name);
 
1152
 
 
1153
  if (oss_register_interrupts (devc->osdev, 0, solointr, NULL) < 0)
 
1154
    {
 
1155
      cmn_err (CE_WARN, "Can't allocate IRQ%d\n", pci_irq_line);
 
1156
      return 0;
 
1157
    }
 
1158
 
 
1159
 
 
1160
  /* Read the VCBase register */
 
1161
  if (pci_ioaddr2 == 0)
 
1162
    {
 
1163
      cmn_err (CE_WARN, "DMA I/O base not set\n");
 
1164
      /*return 0; */
 
1165
    }
 
1166
  /* Copy it's contents to the DDMA register */
 
1167
  pci_write_config_dword (osdev, 0x60, pci_ioaddr2 | 0x1); /* enabled DDMA */
 
1168
  devc->ddma_base = MAP_PCI_IOADDR (devc->osdev, 2, pci_ioaddr2);
 
1169
  devc->ddma_base &= ~0x3;
 
1170
 
 
1171
  /* Init other SB base registers */
 
1172
  if (pci_ioaddr1 == 0)
 
1173
    {
 
1174
      cmn_err (CE_WARN, "SB I/O base not set\n");
 
1175
      return 0;
 
1176
    }
 
1177
  devc->sb_base = MAP_PCI_IOADDR (devc->osdev, 1, pci_ioaddr1);
 
1178
  devc->sb_base &= ~0x3;
 
1179
 
 
1180
 
 
1181
  /* Init MPU base register */
 
1182
  if (pci_ioaddr3 == 0)
 
1183
    {
 
1184
      cmn_err (CE_WARN, "MPU I/O base not set\n");
 
1185
      return 0;
 
1186
    }
 
1187
  devc->mpu_base = MAP_PCI_IOADDR (devc->osdev, 3, pci_ioaddr3);
 
1188
  devc->mpu_base &= ~0x3;
 
1189
 
 
1190
  /* Setup Legacy audio register - disable legacy audio */
 
1191
  pci_write_config_word (osdev, 0x40, 0x805f);
 
1192
 
 
1193
  /* Select DDMA and Disable IRQ emulation */
 
1194
  pci_write_config_dword (osdev, 0x50, 0);
 
1195
  pci_read_config_dword (osdev, 0x50, &pci_ioaddr0);
 
1196
  pci_ioaddr0 &= (~(0x0700 | 0x6000));
 
1197
  pci_write_config_dword (osdev, 0x50, pci_ioaddr0);
 
1198
 
 
1199
  return init_solo (devc);      /* Detected */
 
1200
}
 
1201
 
 
1202
 
 
1203
int
 
1204
oss_solo_detach (oss_device_t * osdev)
 
1205
{
 
1206
  solo_devc *devc = (solo_devc *) osdev->devc;
 
1207
 
 
1208
  if (oss_disable_device (osdev) < 0)
 
1209
    return 0;
 
1210
 
 
1211
  /* disable all interrupts */
 
1212
  /*OUTB (devc->osdev, 0, devc->base + 7); */
 
1213
 
 
1214
#ifdef OBSOLETED_STUFF
 
1215
  if (devc->mpu_attached)
 
1216
    unload_mpu (devc);
 
1217
#endif
 
1218
 
 
1219
  oss_unregister_interrupts (devc->osdev);
 
1220
 
 
1221
  MUTEX_CLEANUP (devc->mutex);
 
1222
  MUTEX_CLEANUP (devc->low_mutex);
 
1223
  UNMAP_PCI_IOADDR (devc->osdev, 0);
 
1224
  UNMAP_PCI_IOADDR (devc->osdev, 1);
 
1225
  UNMAP_PCI_IOADDR (devc->osdev, 2);
 
1226
  UNMAP_PCI_IOADDR (devc->osdev, 3);
 
1227
 
 
1228
  oss_unregister_device (devc->osdev);
 
1229
  return 1;
 
1230
}