OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [sound/] [lowlevel/] [aci.c] - Blame information for rev 1626

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 * Audio Command Interface (ACI) driver (sound/aci.c)
3
 *
4
 * ACI is a protocol used to communicate with the microcontroller on
5
 * some sound cards produced by miro, e.g. the miroSOUND PCM12 and
6
 * PCM20. The ACI has been developed for miro by Norberto Pellicci
7
 * <pellicci@ix.netcom.com>. Special thanks to both him and miro for
8
 * providing the ACI specification.
9
 *
10
 * The main function of the ACI is to control the mixer and to get a
11
 * product identification. On the PCM20, ACI also controls the radio
12
 * tuner on this card, however this is not yet supported in this
13
 * software.
14
 *
15
 * This Voxware ACI driver currently only supports the ACI functions
16
 * on the miroSOUND PCM12 card. Support for miro soundcards with
17
 * additional ACI functions can easily be added later.
18
 *
19
 * Revision history:
20
 *
21
 *   1995-11-10  Markus Kuhn <mskuhn@cip.informatik.uni-erlangen.de>
22
 *        First version written.
23
 *   1995-12-31  Markus Kuhn
24
 *        Second revision, general code cleanup.
25
 *   1996-05-16  Hannu Savolainen
26
 *        Integrated with other parts of the driver.
27
 *   1996-05-28  Markus Kuhn
28
 *        Initialize CS4231A mixer, make ACI first mixer,
29
 *        use new private mixer API for solo mode.
30
 */
31
 
32
/*
33
 * Some driver specific information and features:
34
 *
35
 * This mixer driver identifies itself to applications as "ACI" in
36
 * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
37
 *
38
 * Proprietary mixer features that go beyond the standard USS mixer
39
 * interface are:
40
 *
41
 * Full duplex solo configuration:
42
 *
43
 *   int solo_mode;
44
 *   ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode);
45
 *
46
 *   solo_mode = 0: deactivate solo mode (default)
47
 *   solo_mode > 0: activate solo mode
48
 *                  With activated solo mode, the PCM input can not any
49
 *                  longer hear the signals produced by the PCM output.
50
 *                  Activating solo mode is important in duplex mode in order
51
 *                  to avoid feedback distortions.
52
 *   solo_mode < 0: do not change solo mode (just retrieve the status)
53
 *
54
 *   When the ioctl() returns 0, solo_mode contains the previous
55
 *   status (0 = deactivated, 1 = activated). If solo mode is not
56
 *   implemented on this card, ioctl() returns -1 and sets errno to
57
 *   EINVAL.
58
 *
59
 */
60
 
61
#include <linux/config.h> /* CONFIG_ACI_MIXER */
62
#include "../sound_config.h"
63
#ifdef CONFIG_ACI_MIXER
64
 
65
#undef  DEBUG             /* if defined, produce a verbose report via syslog */
66
 
67
int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */
68
unsigned char aci_idcode[2] = {0, 0};         /* manufacturer and product ID */
69
unsigned char aci_version = 0;                       /* ACI firmware version */
70
int aci_solo;                     /* status bit of the card that can't be    *
71
                                   * checked with ACI versions prior to 0xb0 */
72
 
73
static int aci_present = 0;
74
 
75
#define COMMAND_REGISTER    (aci_port)
76
#define STATUS_REGISTER     (aci_port + 1)
77
#define BUSY_REGISTER       (aci_port + 2)
78
 
79
/*
80
 * Wait until the ACI microcontroller has set the READYFLAG in the
81
 * Busy/IRQ Source Register to 0. This is required to avoid
82
 * overrunning the soundcard microcontroller. We do a busy wait here,
83
 * because the microcontroller is not supposed to signal a busy
84
 * condition for more than a few clock cycles. In case of a time-out,
85
 * this function returns -1.
86
 *
87
 * This busy wait code normally requires less than 15 loops and
88
 * practically always less than 100 loops on my i486/DX2 66 MHz.
89
 *
90
 * Warning: Waiting on the general status flag after reseting the MUTE
91
 * function can take a VERY long time, because the PCM12 does some kind
92
 * of fade-in effect. For this reason, access to the MUTE function has
93
 * not been implemented at all.
94
 */
95
 
96
static int busy_wait(void)
97
{
98
  long timeout;
99
 
100
  for (timeout = 0; timeout < 10000000L; timeout++)
101
    if ((inb_p(BUSY_REGISTER) & 1) == 0)
102
      return 0;
103
 
104
#ifdef DEBUG
105
  printk("ACI: READYFLAG timed out.\n");
106
#endif
107
 
108
  return -1;
109
}
110
 
111
 
112
/*
113
 * Read the GENERAL STATUS register.
114
 */
115
 
116
static int read_general_status(void)
117
{
118
  unsigned long flags;
119
  int status;
120
 
121
  save_flags(flags);
122
  cli();
123
  if (busy_wait()) { restore_flags(flags); return -1; }
124
  status = (unsigned) inb_p(STATUS_REGISTER);
125
  restore_flags(flags);
126
  return status;
127
}
128
 
129
 
130
/*
131
 * The four ACI command types (implied, write, read and indexed) can
132
 * be sent to the microcontroller using the following four functions.
133
 * If a problem occurred, they return -1.
134
 */
135
 
136
static int implied_cmd(unsigned char opcode)
137
{
138
  unsigned long flags;
139
 
140
#ifdef DEBUG
141
  printk("ACI: implied_cmd(0x%02x)\n", opcode);
142
#endif
143
 
144
  save_flags(flags);
145
  cli();
146
 
147
  if (read_general_status() < 0 || busy_wait()) {
148
    restore_flags(flags);
149
    return -1;
150
  }
151
  outb_p(opcode, COMMAND_REGISTER);
152
 
153
  restore_flags(flags);
154
  return 0;
155
}
156
 
157
 
158
static int write_cmd(unsigned char opcode, unsigned char parameter)
159
{
160
  unsigned long flags;
161
  int status;
162
 
163
#ifdef DEBUG
164
  printk("ACI: write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
165
#endif
166
 
167
  save_flags(flags);
168
  cli();
169
 
170
  if (read_general_status() < 0 || busy_wait()) {
171
    restore_flags(flags);
172
    return -1;
173
  }
174
  outb_p(opcode, COMMAND_REGISTER);
175
  if (busy_wait()) { restore_flags(flags); return -1; }
176
  outb_p(parameter, COMMAND_REGISTER);
177
 
178
  if ((status = read_general_status()) < 0) {
179
    restore_flags(flags);
180
    return -1;
181
  }
182
  /* polarity of the INVALID flag depends on ACI version */
183
  if ((aci_version <  0xb0 && (status & 0x40) != 0) ||
184
      (aci_version >= 0xb0 && (status & 0x40) == 0)) {
185
    restore_flags(flags);
186
    printk("ACI: invalid write command 0x%02x, 0x%02x.\n",
187
           opcode, parameter);
188
    return -1;
189
  }
190
 
191
  restore_flags(flags);
192
  return 0;
193
}
194
 
195
 
196
static int read_cmd(unsigned char opcode, int length, unsigned char *parameter)
197
{
198
  unsigned long flags;
199
  int i = 0;
200
 
201
  save_flags(flags);
202
  cli();
203
 
204
  if (read_general_status() < 0) { restore_flags(flags); return -1; }
205
  while (i < length) {
206
    if (busy_wait()) { restore_flags(flags); return -1; }
207
    outb_p(opcode, COMMAND_REGISTER);
208
    if (busy_wait()) { restore_flags(flags); return -1; }
209
    parameter[i++] = inb_p(STATUS_REGISTER);
210
#ifdef DEBUG
211
    if (i == 1)
212
      printk("ACI: read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length,
213
             parameter[i-1]);
214
    else
215
      printk("ACI: read_cmd cont.: 0x%02x\n", parameter[i-1]);
216
#endif
217
  }
218
 
219
  restore_flags(flags);
220
  return 0;
221
}
222
 
223
 
224
static int indexed_cmd(unsigned char opcode, unsigned char index,
225
                       unsigned char *parameter)
226
{
227
  unsigned long flags;
228
 
229
  save_flags(flags);
230
  cli();
231
 
232
  if (read_general_status() < 0 || busy_wait()) {
233
    restore_flags(flags);
234
    return -1;
235
  }
236
  outb_p(opcode, COMMAND_REGISTER);
237
  if (busy_wait()) { restore_flags(flags); return -1; }
238
  outb_p(index, COMMAND_REGISTER);
239
  if (busy_wait()) { restore_flags(flags); return -1; }
240
  *parameter = inb_p(STATUS_REGISTER);
241
#ifdef DEBUG
242
  printk("ACI: indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
243
         *parameter);
244
#endif
245
 
246
  restore_flags(flags);
247
  return 0;
248
}
249
 
250
 
251
/*
252
 * The following macro SCALE can be used to scale one integer volume
253
 * value into another one using only integer arithmetic. If the input
254
 * value x is in the range 0 <= x <= xmax, then the result will be in
255
 * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
256
 *
257
 * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
258
 * following nice properties:
259
 *
260
 * - SCALE(xmax,ymax,xmax) = ymax
261
 * - SCALE(xmax,ymax,0) = 0
262
 * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
263
 *
264
 * In addition, the rounding error is minimal and nicely distributed.
265
 * The proofs are left as an exercise to the reader.
266
 */
267
 
268
#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
269
 
270
 
271
static int getvolume(caddr_t arg,
272
                     unsigned char left_index, unsigned char right_index)
273
{
274
  int vol;
275
  unsigned char buf;
276
 
277
  /* left channel */
278
  if (indexed_cmd(0xf0, left_index, &buf)) return -EIO;
279
  vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
280
  /* right channel */
281
  if (indexed_cmd(0xf0, right_index, &buf)) return -EIO;
282
  vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
283
 
284
  return snd_ioctl_return((int *) arg, vol);
285
}
286
 
287
 
288
static int setvolume(caddr_t arg,
289
                     unsigned char left_index, unsigned char right_index)
290
{
291
  int vol, ret;
292
  unsigned param;
293
 
294
  param = get_user((int *) arg);
295
  /* left channel */
296
  vol = param & 0xff;
297
  if (vol > 100) vol = 100;
298
  vol = SCALE(100, 0x20, vol);
299
  if (write_cmd(left_index, 0x20 - vol)) return -EIO;
300
  ret = SCALE(0x20, 100, vol);
301
  /* right channel */
302
  vol = (param >> 8) & 0xff;
303
  if (vol > 100) vol = 100;
304
  vol = SCALE(100, 0x20, vol);
305
  if (write_cmd(right_index, 0x20 - vol)) return -EIO;
306
  ret |= SCALE(0x20, 100, vol) << 8;
307
 
308
  return snd_ioctl_return((int *) arg, ret);
309
}
310
 
311
 
312
static int
313
aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
314
{
315
  int status, vol;
316
  unsigned char buf;
317
 
318
  /* handle solo mode control */
319
  if (cmd == SOUND_MIXER_PRIVATE1) {
320
    if (get_user((int *) arg) >= 0) {
321
      aci_solo = !!get_user((int *) arg);
322
      if (write_cmd(0xd2, aci_solo)) return -EIO;
323
    } else if (aci_version >= 0xb0) {
324
      if ((status = read_general_status()) < 0) return -EIO;
325
      return snd_ioctl_return ((int *) arg, (status & 0x20) == 0);
326
    }
327
    return snd_ioctl_return((int *) arg, aci_solo);
328
  }
329
 
330
  if (((cmd >> 8) & 0xff) == 'M') {
331
    if (cmd & IOC_IN)
332
      /* read and write */
333
      switch (cmd & 0xff) {
334
      case SOUND_MIXER_VOLUME:
335
        return setvolume(arg, 0x01, 0x00);
336
      case SOUND_MIXER_CD:
337
        return setvolume(arg, 0x3c, 0x34);
338
      case SOUND_MIXER_MIC:
339
        return setvolume(arg, 0x38, 0x30);
340
      case SOUND_MIXER_LINE:
341
        return setvolume(arg, 0x39, 0x31);
342
      case SOUND_MIXER_SYNTH:
343
        return setvolume(arg, 0x3b, 0x33);
344
      case SOUND_MIXER_PCM:
345
        return setvolume(arg, 0x3a, 0x32);
346
      case SOUND_MIXER_LINE1:  /* AUX1 */
347
        return setvolume(arg, 0x3d, 0x35);
348
      case SOUND_MIXER_LINE2:  /* AUX2 */
349
        return setvolume(arg, 0x3e, 0x36);
350
      case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
351
        vol = get_user((int *) arg) & 0xff;
352
        if (vol > 100) vol = 100;
353
        vol = SCALE(100, 3, vol);
354
        if (write_cmd(0x03, vol)) return -EIO;
355
        vol = SCALE(3, 100, vol);
356
        return snd_ioctl_return((int *) arg, vol | (vol << 8));
357
      case SOUND_MIXER_RECSRC:
358
        return snd_ioctl_return ((int *) arg, 0);
359
        break;
360
      default:
361
        return -EINVAL;
362
      }
363
    else
364
      /* only read */
365
      switch (cmd & 0xff) {
366
      case SOUND_MIXER_DEVMASK:
367
        return snd_ioctl_return ((int *) arg,
368
                                 SOUND_MASK_VOLUME | SOUND_MASK_CD    |
369
                                 SOUND_MASK_MIC    | SOUND_MASK_LINE  |
370
                                 SOUND_MASK_SYNTH  | SOUND_MASK_PCM   |
371
#if 0
372
                                 SOUND_MASK_IGAIN  |
373
#endif
374
                                 SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
375
        break;
376
      case SOUND_MIXER_STEREODEVS:
377
        return snd_ioctl_return ((int *) arg,
378
                                 SOUND_MASK_VOLUME | SOUND_MASK_CD   |
379
                                 SOUND_MASK_MIC    | SOUND_MASK_LINE |
380
                                 SOUND_MASK_SYNTH  | SOUND_MASK_PCM  |
381
                                 SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
382
        break;
383
      case SOUND_MIXER_RECMASK:
384
        return snd_ioctl_return ((int *) arg, 0);
385
        break;
386
      case SOUND_MIXER_RECSRC:
387
        return snd_ioctl_return ((int *) arg, 0);
388
        break;
389
      case SOUND_MIXER_CAPS:
390
        return snd_ioctl_return ((int *) arg, 0);
391
        break;
392
      case SOUND_MIXER_VOLUME:
393
        return getvolume(arg, 0x04, 0x03);
394
      case SOUND_MIXER_CD:
395
        return getvolume(arg, 0x0a, 0x09);
396
      case SOUND_MIXER_MIC:
397
        return getvolume(arg, 0x06, 0x05);
398
      case SOUND_MIXER_LINE:
399
        return getvolume(arg, 0x08, 0x07);
400
      case SOUND_MIXER_SYNTH:
401
        return getvolume(arg, 0x0c, 0x0b);
402
      case SOUND_MIXER_PCM:
403
        return getvolume(arg, 0x0e, 0x0d);
404
      case SOUND_MIXER_LINE1:  /* AUX1 */
405
        return getvolume(arg, 0x11, 0x10);
406
      case SOUND_MIXER_LINE2:  /* AUX2 */
407
        return getvolume(arg, 0x13, 0x12);
408
      case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
409
        if (indexed_cmd(0xf0, 0x21, &buf)) return -EIO;
410
        vol = SCALE(3, 100, buf <= 3 ? buf : 3);
411
        vol |= vol << 8;
412
        return snd_ioctl_return((int *) arg, vol);
413
      default:
414
        return -EINVAL;
415
      }
416
  }
417
 
418
  return -EINVAL;
419
}
420
 
421
 
422
static struct mixer_operations aci_mixer_operations =
423
{
424
  "ACI",
425
  "ACI mixer",
426
  aci_mixer_ioctl,
427
  NULL
428
};
429
 
430
static unsigned char
431
mad_read (int port)
432
{
433
  outb (0xE3, 0xf8f); /* Write MAD16 password */
434
  return inb (port);  /* Read from port */
435
}
436
 
437
 
438
/*
439
 * Check, whether there actually is any ACI port operational and if
440
 * one was found, then initialize the ACI interface, reserve the I/O
441
 * addresses and attach the new mixer to the relevant VoxWare data
442
 * structures.
443
 *
444
 * Returns:  1   ACI mixer detected
445
 *           0   nothing there
446
 *
447
 * There is also an internal mixer in the codec (CS4231A or AD1845),
448
 * that deserves no purpose in an ACI based system which uses an
449
 * external ACI controlled stereo mixer. Make sure that this codec
450
 * mixer has the AUX1 input selected as the recording source, that the
451
 * input gain is set near maximum and that the other channels going
452
 * from the inputs to the codec output are muted.
453
 */
454
 
455
int attach_aci(void)
456
{
457
  char *boardname = "unknown";
458
  int volume;
459
 
460
#define MC4_PORT        0xf90
461
 
462
  aci_port =
463
      (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;
464
 
465
  if (check_region(aci_port, 3)) {
466
#ifdef DEBUG
467
    printk("ACI: I/O area 0x%03x-0x%03x already used.\n",
468
           aci_port, aci_port+2);
469
#endif
470
    return 0;
471
  }
472
 
473
  if (read_cmd(0xf2, 2, aci_idcode)) {
474
#ifdef DEBUG
475
    printk("ACI: Failed to read idcode.\n");
476
#endif
477
    return 0;
478
  }
479
  if (read_cmd(0xf1, 1, &aci_version)) {
480
#ifdef DEBUG
481
    printk("ACI: Failed to read version.\n");
482
#endif
483
    return 0;
484
  }
485
 
486
  if (aci_idcode[0] == 0x6d) {
487
    /* it looks like a miro soundcard */
488
    switch (aci_idcode[1]) {
489
    case 0x41:
490
      boardname = "PCM1 pro / early PCM12";
491
      break;
492
    case 0x42:
493
      boardname = "PCM12";
494
      break;
495
    case 0x43:
496
      boardname = "PCM20";
497
      break;
498
    default:
499
      boardname = "unknown miro";
500
    }
501
  } else
502
#ifndef DEBUG
503
    return 0;
504
#endif
505
 
506
  printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",
507
         aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);
508
 
509
  /* initialize ACI mixer */
510
  implied_cmd(0xff);
511
  aci_solo = 0;
512
 
513
  /* attach the mixer */
514
  request_region(aci_port, 3, "sound mixer (ACI)");
515
  if (num_mixers < MAX_MIXER_DEV) {
516
    if (num_mixers > 0 &&
517
        !strcmp("MAD16 WSS (CS4231A)", mixer_devs[num_mixers-1]->name)) {
518
      /*
519
       * The previously registered mixer device is the CS4231A which
520
       * has no function on an ACI card. Make the ACI mixer the first
521
       * of the two mixer devices.
522
       */
523
      mixer_devs[num_mixers] = mixer_devs[num_mixers-1];
524
      mixer_devs[num_mixers-1] = &aci_mixer_operations;
525
      /*
526
       * Initialize the CS4231A mixer with reasonable values. It is
527
       * unlikely that the user ever will want to change these as all
528
       * channels can be mixed via ACI.
529
       */
530
      volume = 0x6464;
531
      mixer_devs[num_mixers]->
532
        ioctl(num_mixers, SOUND_MIXER_WRITE_PCM,     (caddr_t) &volume);
533
      volume = 0x6464;
534
      mixer_devs[num_mixers]->
535
        ioctl(num_mixers, SOUND_MIXER_WRITE_IGAIN,   (caddr_t) &volume);
536
      volume = 0;
537
      mixer_devs[num_mixers]->
538
        ioctl(num_mixers, SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);
539
      volume = 0;
540
      mixer_devs[num_mixers]->
541
        ioctl(num_mixers, SOUND_MIXER_WRITE_MIC,     (caddr_t) &volume);
542
      volume = 0;
543
      mixer_devs[num_mixers]->
544
        ioctl(num_mixers, SOUND_MIXER_WRITE_IMIX,    (caddr_t) &volume);
545
      volume = 0;
546
      mixer_devs[num_mixers]->
547
        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE1,   (caddr_t) &volume);
548
      volume = 0;
549
      mixer_devs[num_mixers]->
550
        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE2,   (caddr_t) &volume);
551
      volume = 0;
552
      mixer_devs[num_mixers]->
553
        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE3,   (caddr_t) &volume);
554
      volume = SOUND_MASK_LINE1;
555
      mixer_devs[num_mixers]->
556
        ioctl(num_mixers, SOUND_MIXER_WRITE_RECSRC,  (caddr_t) &volume);
557
      num_mixers++;
558
    } else
559
      mixer_devs[num_mixers++] = &aci_mixer_operations;
560
  }
561
 
562
  /* Initialize ACI mixer with reasonable power-up values */
563
  volume = 0x3232;
564
  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);
565
  volume = 0x3232;
566
  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH,  (caddr_t) &volume);
567
  volume = 0x3232;
568
  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM,    (caddr_t) &volume);
569
  volume = 0x3232;
570
  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE,   (caddr_t) &volume);
571
  volume = 0x3232;
572
  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC,    (caddr_t) &volume);
573
  volume = 0x3232;
574
  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD,     (caddr_t) &volume);
575
  volume = 0x3232;
576
  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1,  (caddr_t) &volume);
577
  volume = 0x3232;
578
  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2,  (caddr_t) &volume);
579
 
580
  aci_present = 1;
581
 
582
  return 1;
583
}
584
 
585
void unload_aci(void)
586
{
587
  if (aci_present)
588
    release_region(aci_port, 3);
589
}
590
 
591
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.