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

« back to all changes in this revision

Viewing changes to kernel/framework/audio/oss_audio_core.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: Audio core functionality of OSS
 
3
 */
 
4
 
 
5
/*
 
6
 *
 
7
 * This file is part of Open Sound System.
 
8
 *
 
9
 * Copyright (C) 4Front Technologies 1996-2008.
 
10
 *
 
11
 * This this source file is released under GPL v2 license (no other versions).
 
12
 * See the COPYING file included in the main directory of this source
 
13
 * distribution for the license terms and conditions.
 
14
 *
 
15
 */
 
16
 
 
17
#undef  NO_COOKED_MODE
 
18
#define AUDIO_C
 
19
 
 
20
#define GRC     3
 
21
 
 
22
/* Some debugging macros (for future use) */
 
23
#define UP_STATUS(x)
 
24
#define DOWN_STATUS(x)
 
25
 
 
26
#include <oss_config.h>
 
27
 
 
28
extern int src_quality;
 
29
extern int vmix_disabled;
 
30
extern int excl_policy;
 
31
 
 
32
oss_mutex_t audio_global_mutex;
 
33
 
 
34
/*
 
35
 * Resizeable audio device tables
 
36
 */
 
37
static oss_memblk_t *audio_global_memblk=NULL;
 
38
int oss_max_audio_devfiles=4;
 
39
int oss_max_audio_engines=8;
 
40
#define AUDIO_MALLOC(osdev, size) oss_memblk_malloc(&audio_global_memblk, size)
 
41
#define AUDIO_FREE(osdev, addr) oss_memblk_free(&audio_global_memblk, addr)
 
42
#define AUDIO_ENGINE_INCREMENT  (oss_max_audio_engines/2)
 
43
#define AUDIO_DEVFILE_INCREMENT (oss_max_audio_devfiles/2)
 
44
 
 
45
/*
 
46
 * List of audio devices in the system
 
47
 */
 
48
adev_t **audio_engines = NULL;
 
49
int num_audio_engines = 0;
 
50
 
 
51
adev_t **audio_devfiles = NULL;
 
52
int num_audio_devfiles = 0;
 
53
extern int flat_device_model;
 
54
 
 
55
#if 0
 
56
/*
 
57
 * Device lists (input, output, duplex) for /dev/dsp.
 
58
 */
 
59
 
 
60
oss_devlist_t dspinlist = { 0 };
 
61
oss_devlist_t dspoutlist = { 0 };
 
62
oss_devlist_t dspinoutlist = { 0 };
 
63
oss_devlist_t dspoutlist2 = { 0 };      /* 2nd priority output devices */
 
64
#endif
 
65
 
 
66
/*
 
67
 * Applications known to require special handling (mmap, etc.). These 
 
68
 * applications are listed here because they use the OSS API incorrectly and
 
69
 * some workarounds by OSS are required to make them to work.
 
70
 */
 
71
typedef struct
 
72
{
 
73
  char *name;
 
74
  int open_flags;
 
75
} oss_specialapp_t;
 
76
 
 
77
oss_specialapp_t special_apps[] = {
 
78
  {"quake", OF_MMAP},
 
79
  {"quake2", OF_MMAP},
 
80
  {"q3demo.x86", OF_MMAP},
 
81
  {"wolfsp.x86", OF_MMAP},
 
82
  {"wolfmp.x86", OF_MMAP},
 
83
  {"quake3", OF_MMAP},
 
84
  {"wolf3d", OF_MMAP},
 
85
  {"rtcw", OF_MMAP},
 
86
  {"artsd", OF_BLOCK | OF_NOCONV},
 
87
  {"realplay.bin", OF_SMALLFRAGS},
 
88
  {"hxplay.bin", OF_SMALLFRAGS},
 
89
#if 1
 
90
  {"auserver", OF_NOCONV},      /* Win4lin */
 
91
#endif
 
92
  {"quake3.x86", OF_MMAP},
 
93
  {"wolf.x86", OF_MMAP},
 
94
  {"et.x86", OF_MMAP},
 
95
  {"doom.x86", OF_MMAP},
 
96
  // {"mozilla-bin", OF_MEDIUMBUF}, /* For the flash plugin */
 
97
  {NULL, 0}
 
98
};
 
99
 
 
100
#ifdef APPLIST_SUPPORT
 
101
/*
 
102
 * Lookup tables for applications. Use these lists to assign
 
103
 * fixed target devices for given applications.
 
104
 */
 
105
 
 
106
app_routing_t oss_applist[APPLIST_SIZE];
 
107
int oss_applist_size = 0;
 
108
 
 
109
static int
 
110
app_lookup (int mode, const char *appname, int *open_flags)
 
111
{
 
112
  int i, dev;
 
113
 
 
114
  if (appname == NULL)
 
115
    return -2;
 
116
 
 
117
  for (i = 0; i < oss_applist_size; i++)
 
118
    {
 
119
      if (oss_applist[i].mode == mode)
 
120
        if (strncmp (appname, oss_applist[i].name, 32) == 0)
 
121
          {
 
122
            dev = oss_applist[i].dev;
 
123
 
 
124
            if (dev < -1 || dev >= num_audio_devfiles)
 
125
              return -1;
 
126
            *open_flags |= oss_applist[i].open_flags;
 
127
            return dev;
 
128
          }
 
129
    }
 
130
 
 
131
  return -2;
 
132
}
 
133
#endif
 
134
 
 
135
/*ARGSUSED*/
 
136
static int
 
137
get_open_flags (int mode, int open_flags, struct fileinfo *file)
 
138
{
 
139
  char *name;
 
140
  int i;
 
141
 
 
142
  if ((name = GET_PROCESS_NAME (file)) != NULL)
 
143
    {
 
144
#ifdef APPLIST_SUPPORT
 
145
      if (app_lookup (mode, name, &open_flags) >= -1)
 
146
        return open_flags;
 
147
#endif
 
148
 
 
149
      for (i = 0; special_apps[i].name != NULL; i++)
 
150
        if (strcmp (special_apps[i].name, name) == 0)
 
151
          {
 
152
            open_flags |= special_apps[i].open_flags;
 
153
            return open_flags;
 
154
          }
 
155
    }
 
156
 
 
157
  return open_flags;
 
158
}
 
159
 
 
160
#define BIGWRITE_SIZE   1024
 
161
 
 
162
#define NEUTRAL8        0x80
 
163
#define NEUTRAL16       0x00
 
164
#define OSS_PLUGIN_VERSION              (0x100|oss_sample_bits)
 
165
 
 
166
int always_cooked = 0;
 
167
static unsigned long sync_seed = 0;
 
168
 
 
169
#define COOKED_BLOCK_SIZE 4096
 
170
 
 
171
extern oss_uint64_t oss_tmp_timer;
 
172
 
 
173
/*
 
174
 * Structure used by oss_audio_register_client()
 
175
 */
 
176
typedef struct
 
177
{
 
178
  oss_audio_startup_func func;
 
179
  void *devc;
 
180
  oss_device_t *osdev;
 
181
} audio_startup_t;
 
182
 
 
183
#define MAX_STARTUPS    5
 
184
static audio_startup_t audio_startups[MAX_STARTUPS];
 
185
static int num_audio_startups = 0;
 
186
 
 
187
int
 
188
dmap_get_qlen (dmap_p dmap)
 
189
{
 
190
  int len;
 
191
 
 
192
  if (dmap->dma_mode == PCM_ENABLE_OUTPUT)
 
193
    {
 
194
      if (dmap->fragment_size == 0)
 
195
        {
 
196
          cmn_err (CE_WARN, "dmap (out) fragment_size=0, dev=%s\n",
 
197
                   dmap->adev->name);
 
198
          return 0;
 
199
        }
 
200
 
 
201
      len =
 
202
        (int) ((dmap->user_counter -
 
203
                dmap->byte_counter) / dmap->fragment_size);
 
204
      if (len < 0)
 
205
        len = 0;
 
206
      return len;
 
207
    }
 
208
 
 
209
  if (dmap->dma_mode == PCM_ENABLE_INPUT)
 
210
    {
 
211
      if (dmap->fragment_size == 0)
 
212
        {
 
213
          cmn_err (CE_WARN, "dmap (in) fragment_size=0, dev=%s\n",
 
214
                   dmap->adev->name);
 
215
          return 0;
 
216
        }
 
217
 
 
218
      len =
 
219
        (int) ((dmap->byte_counter -
 
220
                dmap->user_counter) / dmap->fragment_size);
 
221
      if (len < 0)
 
222
        len = 0;
 
223
      return len;
 
224
    }
 
225
 
 
226
  return 0;
 
227
}
 
228
 
 
229
int
 
230
dmap_get_qhead (dmap_p dmap)
 
231
{
 
232
  unsigned int ptr;
 
233
 
 
234
  if (dmap->fragment_size == 0)
 
235
    return 0;
 
236
 
 
237
  if (dmap->dma_mode == PCM_ENABLE_OUTPUT)
 
238
    {
 
239
      ptr = (int) (dmap->byte_counter % dmap->bytes_in_use);
 
240
      return ptr / dmap->fragment_size;
 
241
    }
 
242
 
 
243
  if (dmap->dma_mode == PCM_ENABLE_INPUT)
 
244
    {
 
245
      ptr = (int) (dmap->user_counter % dmap->bytes_in_use);
 
246
      return ptr / dmap->fragment_size;
 
247
    }
 
248
 
 
249
  return 0;
 
250
}
 
251
 
 
252
int
 
253
dmap_get_qtail (dmap_p dmap)
 
254
{
 
255
  unsigned int ptr;
 
256
 
 
257
  if (dmap->fragment_size == 0)
 
258
    return 0;
 
259
 
 
260
  if (dmap->dma_mode == PCM_ENABLE_INPUT)
 
261
    {
 
262
      ptr = (int) (dmap->byte_counter % dmap->bytes_in_use);
 
263
      return ptr / dmap->fragment_size;
 
264
    }
 
265
 
 
266
  if (dmap->dma_mode == PCM_ENABLE_OUTPUT)
 
267
    {
 
268
      ptr = (int) (dmap->user_counter % dmap->bytes_in_use);
 
269
      return ptr / dmap->fragment_size;
 
270
    }
 
271
 
 
272
  return 0;
 
273
}
 
274
 
 
275
int
 
276
oss_audio_set_format (int dev, int fmt, int format_mask)
 
277
{
 
278
  adev_p adev;
 
279
  int ret, newfmt;
 
280
  unsigned char neutral_byte;
 
281
  audio_format_info_p fmt_info;
 
282
 
 
283
  sync_seed++;
 
284
 
 
285
  if (dev < 0 || dev >= num_audio_engines)
 
286
    return OSS_ENXIO;
 
287
 
 
288
  adev = audio_engines[dev];
 
289
  if (!adev->enabled)
 
290
    return OSS_ENXIO;
 
291
 
 
292
  if (fmt == 0)
 
293
    return adev->user_parms.fmt;
 
294
 
 
295
  if (fmt == AFMT_AC3)
 
296
    {
 
297
      /*
 
298
       * AC3 cannot tolerate any format/rate conversions so disable them.
 
299
       */
 
300
      adev->cooked_enable = 0;
 
301
 
 
302
      /*
 
303
       * Report EIO error if the application tries to do something stupid. 
 
304
       * Otherwise buggy applications may produce loud helicopter sound.
 
305
       */
 
306
 
 
307
      if (adev->flags & ADEV_VMIX)
 
308
        {
 
309
          oss_audio_set_error (adev->engine_num, E_REC,
 
310
                               OSSERR (1018,
 
311
                                       "AFMT_AC3 used with virtual mixing device."),
 
312
                               0);
 
313
          /*
 
314
           * Errordesc:
 
315
           * Devices that support virtual or hardware mixing are
 
316
           * probably not capable to play AC3 streams properly.
 
317
           *
 
318
           * Virtual mixing is enabled on the audio device. The virtual
 
319
           * mixer driver will do voolume control that corrupts the AC3
 
320
           * bitstream. Applications using AC3 should
 
321
           * open the audio device with O_EXCL to make sure that virtual
 
322
           * mixing is properly bypassed.
 
323
           */
 
324
           return OSS_EIO;
 
325
        }
 
326
 
 
327
      if (adev->flags & ADEV_HWMIX)
 
328
        {
 
329
          oss_audio_set_error (adev->engine_num, E_REC,
 
330
                               OSSERR (1019,
 
331
                                       "AFMT_AC3 used with hardware mixing device."),
 
332
                               0);
 
333
          /*
 
334
           * Errordesc:
 
335
           * Devices that support virtual or hardware mixing are
 
336
           * probably not capable to play AC3 streams properly.
 
337
           *
 
338
           * This error may be caused by user who selected a wrong audio
 
339
           * device. 
 
340
           */
 
341
           return OSS_EIO;
 
342
        }
 
343
 
 
344
      if (adev->dmask & DMASK_OUT)
 
345
        if (adev->dmap_out->flags & DMAP_COOKED)
 
346
          {
 
347
            oss_audio_set_error (adev->engine_num, E_REC,
 
348
                                 OSSERR (1020,
 
349
                                         "AFMT_AC3 used with format conversions enabled."),
 
350
                                 0);
 
351
            /*
 
352
             * Errordesc:
 
353
             * AC3 audio format (AFMT_AC3) bitstreams don't tolerate any
 
354
             * kind of sample rate or format conversions. However it looks 
 
355
             * like conversions would be needed. The reason may be that the
 
356
             * application had earlier requested some sample rate that is
 
357
             * not supported by the device.
 
358
             *
 
359
             * Applications using AC3 should call SNDCTL_DSP_COOKEDMODE to
 
360
             * disable format conversions.
 
361
             */
 
362
           return OSS_EIO;
 
363
          }
 
364
    }
 
365
 
 
366
  ret = adev->d->adrv_set_format (dev, fmt);
 
367
 
 
368
  adev->user_parms.fmt = ret;
 
369
  adev->hw_parms.fmt = ret;
 
370
 
 
371
  if ((fmt_info = oss_find_format (ret)) == NULL)
 
372
    neutral_byte = 0;
 
373
  else
 
374
    {
 
375
      neutral_byte = fmt_info->neutral_byte;
 
376
    }
 
377
 
 
378
  if (adev->dmask & DMASK_OUT)
 
379
    adev->dmap_out->neutral_byte = neutral_byte;
 
380
  if (adev->dmask & DMASK_IN)
 
381
    adev->dmap_in->neutral_byte = neutral_byte;
 
382
 
 
383
  /* Disable format conversions if mmap() */
 
384
  if ((adev->dmap_out->mapping_flags & DMA_MAP_MAPPED) ||
 
385
      (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) ||
 
386
      (adev->open_flags & OF_MMAP))
 
387
    return ret;
 
388
 
 
389
#ifdef NO_COOKED_MODE
 
390
  return ret;
 
391
#else
 
392
 
 
393
  if (ret == fmt)
 
394
    return ret;
 
395
 
 
396
  if (!adev->cooked_enable)
 
397
    return ret;
 
398
 
 
399
/*
 
400
 * We need to perform format conversions because the device
 
401
 * doesn't support the requested format.
 
402
 */
 
403
 
 
404
  /* Convertable format? */
 
405
  if (!(fmt & CONVERTABLE_FORMATS))
 
406
    {
 
407
      return ret;
 
408
    }
 
409
 
 
410
  adev->user_parms.fmt = fmt;
 
411
  if (adev->dmask & DMASK_OUT)
 
412
    {
 
413
      adev->dmap_out->flags |= DMAP_COOKED;
 
414
    }
 
415
 
 
416
  if (adev->dmask & DMASK_IN)
 
417
    {
 
418
      adev->dmap_in->flags |= DMAP_COOKED;
 
419
    }
 
420
 
 
421
  /* If the device is in 16 bit format then just return */
 
422
  if (ret & (AFMT_S16_LE | AFMT_S16_BE))
 
423
    return fmt;
 
424
 
 
425
  /* Try to find a suitable format */
 
426
 
 
427
  if (fmt == AFMT_MU_LAW && ret == AFMT_U8)     /* mu-Law <-> 8 bit linear */
 
428
    return fmt;
 
429
 
 
430
  if (format_mask & AFMT_S16_LE)
 
431
    {
 
432
      newfmt = AFMT_S16_LE;
 
433
      goto got_it;
 
434
    }
 
435
 
 
436
  if (format_mask & AFMT_S16_BE)
 
437
    {
 
438
      newfmt = AFMT_S16_BE;
 
439
      goto got_it;
 
440
    }
 
441
 
 
442
  return fmt;                   /* Nothing better than the one suggested by the device */
 
443
got_it:
 
444
 
 
445
  ret = adev->d->adrv_set_format (dev, newfmt);
 
446
 
 
447
  adev->hw_parms.fmt = ret;
 
448
 
 
449
  return fmt;
 
450
#endif
 
451
}
 
452
 
 
453
int
 
454
oss_audio_set_channels (int dev, int ch)
 
455
{
 
456
  adev_p adev;
 
457
  int ret;
 
458
 
 
459
  sync_seed++;
 
460
 
 
461
  if (dev < 0 || dev >= num_audio_engines)
 
462
    return OSS_ENXIO;
 
463
 
 
464
  adev = audio_engines[dev];
 
465
  if (!adev->enabled)
 
466
    return OSS_ENXIO;
 
467
 
 
468
  if (ch == 0)
 
469
    return adev->user_parms.channels;
 
470
 
 
471
  ret = adev->d->adrv_set_channels (dev, ch);
 
472
 
 
473
  if (ret < 1)
 
474
    {
 
475
      cmn_err (CE_WARN,
 
476
               "Audio engine %d: Internal error in channel setup, err=%d, ch=%d\n",
 
477
               dev, ret, ch);
 
478
      return OSS_EIO;
 
479
    }
 
480
 
 
481
  if (ch > 2 && ch > ret)       /* Requested multi channel mode not possible */
 
482
    ch = ret;
 
483
 
 
484
  adev->user_parms.channels = ret;
 
485
  adev->hw_parms.channels = ret;
 
486
 
 
487
  /* Disable format conversions if mmap() */
 
488
  if ((adev->dmap_out->mapping_flags & DMA_MAP_MAPPED) ||
 
489
      (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) ||
 
490
      (adev->open_flags & OF_MMAP))
 
491
    return ret;
 
492
 
 
493
  if (ret > 1 && (adev->flags & ADEV_NONINTERLEAVED))
 
494
  {
 
495
          if (adev->dmask & DMASK_OUT)
 
496
              adev->dmap_out->flags |= DMAP_COOKED;
 
497
        
 
498
          if (adev->dmask & DMASK_IN)
 
499
              adev->dmap_in->flags |= DMAP_COOKED;
 
500
  }
 
501
     
 
502
 
 
503
#ifdef NO_COOKED_MODE
 
504
  return ret;
 
505
#else
 
506
 
 
507
  if (!adev->cooked_enable)
 
508
    return ret;
 
509
 
 
510
  if (ret == ch)
 
511
    return ret;
 
512
 
 
513
  /* For the time being only stereo <->mono is possible */
 
514
  if (ch != ret)
 
515
    if (!((ch == 1 && ret == 2) || (ch == 2 && ret == 1)))
 
516
      return ret;
 
517
 
 
518
/*
 
519
 * Needs to perform format conversions
 
520
 */
 
521
 
 
522
  adev->user_parms.channels = ch;
 
523
  if (adev->dmask & DMASK_OUT)
 
524
    {
 
525
      adev->dmap_out->flags |= DMAP_COOKED;
 
526
    }
 
527
 
 
528
  if (adev->dmask & DMASK_IN)
 
529
    {
 
530
      adev->dmap_in->flags |= DMAP_COOKED;
 
531
    }
 
532
 
 
533
  return ch;
 
534
#endif
 
535
}
 
536
 
 
537
int
 
538
oss_audio_set_rate (int dev, int rate)
 
539
{
 
540
  adev_p adev;
 
541
  int ret;
 
542
 
 
543
  sync_seed++;
 
544
 
 
545
  if (dev < 0 || dev >= num_audio_engines)
 
546
    return OSS_ENXIO;
 
547
 
 
548
  adev = audio_engines[dev];
 
549
  if (!adev->enabled)
 
550
    return OSS_ENXIO;
 
551
 
 
552
  if (rate == 0)
 
553
    return adev->user_parms.rate;
 
554
 
 
555
  ret = adev->d->adrv_set_rate (dev, rate);
 
556
  if (ret < 0)
 
557
    return ret;
 
558
 
 
559
  adev->user_parms.rate = ret;
 
560
  adev->hw_parms.rate = ret;
 
561
 
 
562
  /* Disable format conversions if mmap() */
 
563
  if ((adev->dmap_out->mapping_flags & DMA_MAP_MAPPED) ||
 
564
      (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) ||
 
565
      (adev->flags & ADEV_NOSRC) || (adev->open_flags & OF_MMAP))
 
566
    return ret;
 
567
 
 
568
  if (!adev->cooked_enable)
 
569
    return ret;
 
570
 
 
571
#if defined(NO_COOKED_MODE) || GRC == 0
 
572
  return ret;
 
573
#else
 
574
 
 
575
  if (ret == rate)              /* No SRC needed */
 
576
    return ret;
 
577
 
 
578
/*
 
579
 * Needs to perform format conversions
 
580
 */
 
581
 
 
582
  adev->user_parms.rate = rate;
 
583
  if (adev->dmask & DMASK_OUT)
 
584
    {
 
585
      adev->dmap_out->flags |= DMAP_COOKED;
 
586
    }
 
587
 
 
588
  if (adev->dmask & DMASK_IN)
 
589
    {
 
590
      adev->dmap_in->flags |= DMAP_COOKED;
 
591
    }
 
592
 
 
593
  return rate;
 
594
#endif
 
595
}
 
596
 
 
597
static void
 
598
reset_dmap (dmap_p dmap)
 
599
{
 
600
#ifdef DO_TIMINGS
 
601
  oss_do_timing ("Reset dmap");
 
602
#endif
 
603
  dmap->dma_mode = 0;
 
604
  dmap->flags &= (DMAP_FRAGFIXED | DMAP_COOKED);
 
605
  dmap->byte_counter = dmap->user_counter = 0;
 
606
  dmap->fragment_counter = 0;
 
607
  dmap->interrupt_count = 0;
 
608
  dmap->expand_factor = UNIT_EXPAND;    /* 1:1 */
 
609
  dmap->play_underruns = dmap->rec_overruns = 0;
 
610
  dmap->num_errors = 0;
 
611
  dmap->leftover_bytes = 0;
 
612
  dmap->leftover_buf = NULL;
 
613
}
 
614
 
 
615
int
 
616
oss_alloc_dmabuf (int dev, dmap_p dmap, int direction)
 
617
{
 
618
  adev_t *adev = dmap->adev;
 
619
 
 
620
  if (adev == NULL)
 
621
    {
 
622
      cmn_err (CE_WARN, "oss_alloc_dmabuf: adev==NULL\n");
 
623
      return OSS_EIO;
 
624
    }
 
625
 
 
626
  return __oss_alloc_dmabuf (dev, dmap, adev->dmabuf_alloc_flags,
 
627
                             adev->dmabuf_maxaddr, direction);
 
628
}
 
629
 
 
630
static int
 
631
default_alloc_buffer (int dev, dmap_t * dmap, int direction)
 
632
{
 
633
  int err;
 
634
 
 
635
  if (dmap->dmabuf != NULL)
 
636
    return 0;
 
637
 
 
638
  if ((err = oss_alloc_dmabuf (dev, dmap, direction)) < 0)
 
639
    return err;
 
640
 
 
641
  return 0;
 
642
}
 
643
 
 
644
/*ARGSUSED*/
 
645
static int
 
646
default_free_buffer (int dev, dmap_t * dmap, int direction)
 
647
{
 
648
  if (dmap->dmabuf == NULL)
 
649
    return 0;
 
650
 
 
651
  oss_free_dmabuf (dev, dmap);
 
652
 
 
653
  dmap->dmabuf = NULL;
 
654
  dmap->dmabuf_phys = 0;
 
655
  return 0;
 
656
}
 
657
 
 
658
static int
 
659
init_dmap (adev_p adev, dmap_p dmap, int direction)
 
660
{
 
661
  int retval;
 
662
  int l, static_len;
 
663
  char *p;
 
664
  oss_native_word flags;
 
665
 
 
666
  if (dmap->osdev == NULL)
 
667
    {
 
668
      cmn_err (CE_WARN, "dmap->osdev==NULL\n");
 
669
      return OSS_EIO;
 
670
    }
 
671
 
 
672
  if (dmap->dmabuf == NULL)
 
673
    {
 
674
      if (adev->d->adrv_alloc_buffer != NULL)
 
675
        {
 
676
          retval =
 
677
            adev->d->adrv_alloc_buffer (adev->engine_num, dmap, direction);
 
678
        }
 
679
      else
 
680
        {
 
681
          retval = default_alloc_buffer (adev->engine_num, dmap, direction);
 
682
        }
 
683
      if (retval < 0)
 
684
        {
 
685
          cmn_err (CE_WARN,
 
686
                   "Failed to allocate DMA buffer for audio engine %d/%s\n",
 
687
                   adev->engine_num, adev->name);
 
688
          return retval;
 
689
        }
 
690
 
 
691
      if (dmap->dmabuf_phys == 0)       /* Cannot do mmap */
 
692
        adev->flags |= ADEV_NOMMAP;
 
693
    }
 
694
 
 
695
#ifdef linux
 
696
  if (dmap->dmabuf_phys == 0)
 
697
    adev->flags |= ADEV_NOMMAP;
 
698
#endif
 
699
  dmap->flags &= ~DMAP_FRAGFIXED;
 
700
 
 
701
  l = sizeof (dmap_t);
 
702
  static_len = (oss_native_word) & dmap->flags - (oss_native_word) dmap;
 
703
 
 
704
  p = (char *) &dmap->flags;
 
705
  l -= static_len;
 
706
  if (p != NULL)
 
707
    memset (p, 0, l);           /* Clear all */
 
708
 
 
709
  if (!dmap->buffer_protected && dmap->dmabuf != NULL)
 
710
    memset (dmap->dmabuf, dmap->neutral_byte, dmap->buffsize);
 
711
 
 
712
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
713
  reset_dmap (dmap);
 
714
  dmap->bytes_in_use = dmap->buffsize;
 
715
  dmap->frame_size = 1;
 
716
  dmap->user_frame_size = 1;
 
717
  dmap->flags = 0;
 
718
  dmap->audio_callback = NULL;
 
719
 
 
720
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
721
 
 
722
  return 0;
 
723
}
 
724
 
 
725
void
 
726
audio_reset_adev (adev_p adev)
 
727
{
 
728
  oss_native_word flags, dflags;
 
729
#ifdef DO_TIMINGS
 
730
  oss_do_timing ("Reset input & output\n");
 
731
#endif
 
732
  sync_seed++;
 
733
  if (!adev->enabled)
 
734
    return;
 
735
 
 
736
  dflags = 0;
 
737
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
738
  adev->go = 1;
 
739
  adev->enable_bits = adev->open_mode;
 
740
  if (adev->open_mode & OPEN_WRITE)
 
741
    {
 
742
      dmap_p dmap = adev->dmap_out;
 
743
      dmap->flags &= ~DMAP_PREPARED;
 
744
      memset (dmap->dmabuf, 0, dmap->buffsize);
 
745
    }
 
746
 
 
747
  if (adev->d->adrv_halt_input && adev->d->adrv_halt_output)
 
748
    {
 
749
      if (adev->open_mode & OPEN_READ)
 
750
        {
 
751
          dmap_p dmap = adev->dmap_in;
 
752
          MUTEX_ENTER (dmap->mutex, dflags);
 
753
          dmap->flags &= ~DMAP_PREPARED;
 
754
          if ((dmap->dma_mode == PCM_ENABLE_INPUT)
 
755
              && (dmap->flags & DMAP_STARTED))
 
756
            {
 
757
#ifdef CONFIG_OSSD
 
758
              ossd_event (adev->engine_num, OSSD_EV_RESET_INPUT);
 
759
#endif
 
760
              MUTEX_EXIT (dmap->mutex, dflags);
 
761
              MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
762
              adev->d->adrv_halt_input (adev->engine_num);
 
763
              MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
764
              MUTEX_ENTER (dmap->mutex, dflags);
 
765
              reset_dmap (dmap);
 
766
            }
 
767
          MUTEX_EXIT (dmap->mutex, dflags);
 
768
        }
 
769
      if (adev->open_mode & OPEN_WRITE)
 
770
        {
 
771
          dmap_p dmap = adev->dmap_out;
 
772
          MUTEX_ENTER (dmap->mutex, dflags);
 
773
          if ((dmap->dma_mode == PCM_ENABLE_OUTPUT) &&
 
774
              (dmap->flags & DMAP_STARTED))
 
775
            {
 
776
#ifdef CONFIG_OSSD
 
777
              ossd_event (adev->engine_num, OSSD_EV_RESET_OUTPUT);
 
778
#endif
 
779
              MUTEX_EXIT (dmap->mutex, dflags);
 
780
              MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
781
              adev->d->adrv_halt_output (adev->engine_num);
 
782
              MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
783
              MUTEX_ENTER (dmap->mutex, dflags);
 
784
              reset_dmap (dmap);
 
785
            }
 
786
          MUTEX_EXIT (dmap->mutex, dflags);
 
787
        }
 
788
 
 
789
      MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
790
      return;
 
791
    }
 
792
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
793
 
 
794
#ifdef CONFIG_OSSD
 
795
  ossd_event (adev->engine_num, OSSD_EV_RESET_OUTPUT);
 
796
  ossd_event (adev->engine_num, OSSD_EV_RESET_INPUT);
 
797
#endif
 
798
  adev->d->adrv_halt_io (adev->engine_num);
 
799
 
 
800
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
801
  reset_dmap (adev->dmap_out);
 
802
  reset_dmap (adev->dmap_in);
 
803
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
804
}
 
805
 
 
806
static void
 
807
audio_reset_input (adev_p adev)
 
808
{
 
809
  dmap_p dmap = adev->dmap_in;
 
810
  oss_native_word flags, dflags;
 
811
 
 
812
  dflags = 0;
 
813
  if (!(adev->open_mode & OPEN_READ))
 
814
    return;
 
815
 
 
816
  if (dmap->dma_mode != PCM_ENABLE_INPUT)
 
817
    return;
 
818
 
 
819
  if (!(dmap->flags & DMAP_STARTED))
 
820
    return;
 
821
 
 
822
#ifdef DO_TIMINGS
 
823
  oss_do_timing ("Reset input\n");
 
824
#endif
 
825
  dmap->flags &= ~DMAP_PREPARED;
 
826
 
 
827
  if (adev->d->adrv_halt_input)
 
828
    {
 
829
#ifdef CONFIG_OSSD
 
830
      ossd_event (adev->engine_num, OSSD_EV_RESET_INPUT);
 
831
#endif
 
832
      adev->d->adrv_halt_input (adev->engine_num);
 
833
      MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
834
      reset_dmap (dmap);
 
835
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
836
      return;
 
837
    }
 
838
 
 
839
  adev->d->adrv_halt_io (adev->engine_num);
 
840
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
841
  MUTEX_ENTER (dmap->mutex, dflags);
 
842
  reset_dmap (dmap);
 
843
  MUTEX_EXIT (dmap->mutex, dflags);
 
844
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
845
}
 
846
 
 
847
static void
 
848
audio_reset_output (adev_p adev)
 
849
{
 
850
  dmap_p dmap = adev->dmap_out;
 
851
  oss_native_word flags, dflags;
 
852
  dflags = 0;
 
853
 
 
854
  sync_seed++;
 
855
 
 
856
  if (!(adev->open_mode & OPEN_WRITE))
 
857
    return;
 
858
 
 
859
  if (dmap->dma_mode != PCM_ENABLE_OUTPUT)
 
860
    return;
 
861
 
 
862
  if (!(dmap->flags & DMAP_STARTED))
 
863
    return;
 
864
 
 
865
  dmap->flags &= ~DMAP_PREPARED;
 
866
#ifdef DO_TIMINGS
 
867
  oss_do_timing ("Reset output\n");
 
868
#endif
 
869
 
 
870
  if (adev->d->adrv_halt_output)
 
871
    {
 
872
#ifdef CONFIG_OSSD
 
873
      ossd_event (adev->engine_num, OSSD_EV_RESET_OUTPUT);
 
874
#endif
 
875
      adev->d->adrv_halt_output (adev->engine_num);
 
876
      MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
877
      reset_dmap (dmap);
 
878
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
879
      return;
 
880
    }
 
881
 
 
882
  adev->d->adrv_halt_io (adev->engine_num);
 
883
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
884
  MUTEX_ENTER (dmap->mutex, dflags);
 
885
  reset_dmap (dmap);
 
886
  MUTEX_EXIT (dmap->mutex, dflags);
 
887
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
888
}
 
889
 
 
890
static int launch_output (adev_p adev, dmap_p dmap);
 
891
static int launch_input (adev_p adev, dmap_p dmap);
 
892
 
 
893
static void
 
894
oss_audio_post (adev_p adev)
 
895
{
 
896
  int i, n, p;
 
897
  oss_uint64_t limit;
 
898
  dmap_p dmap = adev->dmap_out;
 
899
 
 
900
  if (!(adev->open_mode & OPEN_WRITE))
 
901
    return;
 
902
  if (dmap->user_counter == 0)
 
903
    return;
 
904
 
 
905
  if (dmap->flags & DMAP_STARTED)
 
906
    return;
 
907
 
 
908
#ifdef DO_TIMINGS
 
909
  oss_do_timing ("Post output\n");
 
910
#endif
 
911
 
 
912
  /* Clean the unused buffer space (in slow way) */
 
913
  limit = dmap->byte_counter + dmap->bytes_in_use;
 
914
  if (limit > dmap->user_counter + dmap->bytes_in_use)
 
915
    limit = dmap->user_counter + dmap->bytes_in_use;
 
916
  n = (int) (limit - dmap->user_counter) + 1;
 
917
  p = (int) (dmap->user_counter % dmap->bytes_in_use);  /* Current ptr */
 
918
  for (i = 0; i < n; i++)
 
919
    {
 
920
      dmap->dmabuf[p] = dmap->neutral_byte;
 
921
      p = (p + 1) % dmap->bytes_in_use;
 
922
    }
 
923
 
 
924
  launch_output (adev, dmap);
 
925
}
 
926
 
 
927
static void
 
928
oss_audio_sync (adev_p adev)
 
929
{
 
930
  dmap_p dmap = adev->dmap_out;
 
931
  oss_uint64_t uc, limit;
 
932
  oss_native_word flags;
 
933
  unsigned int status;
 
934
 
 
935
  int n = 0, loops = 0, tmout = OSS_HZ, i;
 
936
  int prev_underruns;
 
937
 
 
938
  if (dmap->dma_mode != PCM_ENABLE_OUTPUT)
 
939
    return;
 
940
  if (adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)
 
941
    return;
 
942
 
 
943
  if (!(dmap->flags & DMAP_STARTED))
 
944
    oss_audio_post (adev);
 
945
 
 
946
  if (!(dmap->flags & DMAP_STARTED))
 
947
    return;
 
948
 
 
949
  /* Don't wait if output is untriggered */
 
950
  if (adev->go == 0 || !(adev->enable_bits & PCM_ENABLE_OUTPUT))
 
951
    return;
 
952
 
 
953
#ifdef DO_TIMINGS
 
954
  oss_do_timing ("Sync output\n");
 
955
#endif
 
956
 
 
957
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
958
  dmap->flags |= DMAP_POST;
 
959
 
 
960
  uc = dmap->user_counter;
 
961
  prev_underruns = dmap->play_underruns;
 
962
  dmap->play_underruns = 0;
 
963
 
 
964
  while (dmap->play_underruns == 0 && loops++ < dmap->nfrags
 
965
         && dmap->byte_counter < uc)
 
966
    {
 
967
      int p;
 
968
      adev->dmap_out->error = 0;
 
969
      /* Clean the unused buffer space (in a slow but precise way) */
 
970
      limit = dmap->byte_counter + dmap->bytes_in_use;
 
971
      if (limit > dmap->user_counter + dmap->bytes_in_use)
 
972
        limit = dmap->user_counter + dmap->bytes_in_use;
 
973
 
 
974
      p = (int) (dmap->user_counter % dmap->bytes_in_use);      /* Current ptr */
 
975
      n = (int) (limit - dmap->user_counter) + 1;
 
976
      for (i = 0; i < n; i++)
 
977
        {
 
978
          dmap->dmabuf[p] = dmap->neutral_byte;
 
979
          p = (p + 1) % dmap->bytes_in_use;
 
980
        }
 
981
 
 
982
      tmout = (dmap->fragment_size * OSS_HZ) / dmap->data_rate;
 
983
      tmout += OSS_HZ / 10;
 
984
 
 
985
      if (!oss_sleep (adev->out_wq, &dmap->mutex, tmout, &flags, &status))
 
986
        {
 
987
#ifndef __FreeBSD__
 
988
          cmn_err (CE_WARN, "Output timed out (sync) on audio engine %d\n",
 
989
                   adev->engine_num);
 
990
#endif
 
991
          adev->timeout_count++;
 
992
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
993
          FMA_EREPORT(adev->osdev, DDI_FM_DEVICE_STALL, NULL, NULL, NULL);
 
994
          FMA_IMPACT(adev->osdev, DDI_SERVICE_LOST);
 
995
          return;
 
996
        }
 
997
    }
 
998
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
999
 
 
1000
  n = 0;
 
1001
  if (adev->d->adrv_local_qlen) /* Drain the internal queue too */
 
1002
    while (n++ <=
 
1003
           adev->d->adrv_local_qlen (adev->engine_num) / dmap->fragment_size)
 
1004
      {
 
1005
        MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
1006
        audio_engines[adev->engine_num]->dmap_out->error = 0;
 
1007
        tmout = (dmap->fragment_size * OSS_HZ) / dmap->data_rate;
 
1008
        tmout += OSS_HZ / 10;
 
1009
        oss_sleep (adev->out_wq, &dmap->mutex, tmout, &flags, &status);
 
1010
        MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
1011
      }
 
1012
  dmap->play_underruns = prev_underruns;
 
1013
}
 
1014
 
 
1015
static int prepare_output (adev_p adev, dmap_p dmap);
 
1016
static int prepare_input (adev_p adev, dmap_p dmap);
 
1017
 
 
1018
void
 
1019
oss_audio_set_error (int dev, int mode, int err, int parm)
 
1020
{
 
1021
  int i, n;
 
1022
 
 
1023
  dmap_t *dmap;
 
1024
 
 
1025
#ifdef DO_TIMINGS
 
1026
  {
 
1027
    if (mode == E_REC)
 
1028
      oss_timing_printf ("Audio rec error code %05d/%d, engine=%d", err, parm,
 
1029
               mode);
 
1030
    else
 
1031
      oss_timing_printf ("Audio play error code %05d/%d, engine=%d", err, parm,
 
1032
               mode);
 
1033
  }
 
1034
#endif
 
1035
 
 
1036
#if 0
 
1037
  if (mode == E_REC)
 
1038
    cmn_err (CE_CONT, "Audio rec error code %05d/%d, engine=%d\n", err, parm,
 
1039
             mode);
 
1040
  else
 
1041
    cmn_err (CE_CONT, "Audio play error code %05d/%d, engine=%d\n", err, parm,
 
1042
             mode);
 
1043
#endif
 
1044
 
 
1045
  switch (mode)
 
1046
    {
 
1047
    case E_PLAY:
 
1048
      dmap = audio_engines[dev]->dmap_out;
 
1049
      break;
 
1050
    case E_REC:
 
1051
      dmap = audio_engines[dev]->dmap_in;
 
1052
      break;
 
1053
 
 
1054
    default:
 
1055
      dmap = audio_engines[dev]->dmap_out;      /* Actually this would be an error */
 
1056
    }
 
1057
 
 
1058
  n = dmap->num_errors++;
 
1059
  if (n > MAX_AUDIO_ERRORS)
 
1060
    n = MAX_AUDIO_ERRORS;
 
1061
 
 
1062
  if (n > 0)
 
1063
    {
 
1064
 
 
1065
/*
 
1066
 * Move previous errors (if any) upwards in the list.
 
1067
 */
 
1068
      for (i = n; i > 0; i--)
 
1069
        {
 
1070
          dmap->errors[i] = dmap->errors[i - 1];
 
1071
          dmap->error_parms[i] = dmap->error_parms[i - 1];
 
1072
        }
 
1073
    }
 
1074
 
 
1075
  dmap->errors[0] = err;
 
1076
  dmap->error_parms[0] = parm;
 
1077
 
 
1078
}
 
1079
 
 
1080
/*ARGSUSED*/
 
1081
static void
 
1082
report_errors (char *s, const char *hdr, adev_t * adev, dmap_t * dmap,
 
1083
               int bufsize)
 
1084
{
 
1085
  int i, l, j;
 
1086
 
 
1087
  if (bufsize < 30)             /* No space left */
 
1088
    return;
 
1089
 
 
1090
  strcpy (s, hdr);
 
1091
  s += l = strlen (s);
 
1092
  bufsize -= l;
 
1093
 
 
1094
  for (i = 0; i < dmap->num_errors && i < MAX_AUDIO_ERRORS; i++)
 
1095
    {
 
1096
      int dupe = 0;
 
1097
 
 
1098
      if (bufsize < 30)
 
1099
        return;
 
1100
      for (j = 0; !dupe && j < i; j++)
 
1101
        if (dmap->errors[i] == dmap->errors[j])
 
1102
          dupe = 1;
 
1103
 
 
1104
      if (dupe)
 
1105
        continue;
 
1106
 
 
1107
      sprintf (s, " %05d:%d", dmap->errors[i], dmap->error_parms[i]);
 
1108
      s += l = strlen (s);
 
1109
      bufsize -= l;
 
1110
    }
 
1111
}
 
1112
 
 
1113
static void
 
1114
store_history (int dev)
 
1115
{
 
1116
  int p;
 
1117
  char *tmp, *s;
 
1118
 
 
1119
  adev_p adev = audio_engines[dev];
 
1120
 
 
1121
  if (adev->pid == 0)           /* Virtual mixer */
 
1122
    return;
 
1123
 
 
1124
  if (*adev->cmd && strcmp (adev->cmd, "sndconf") == 0)
 
1125
    return;
 
1126
 
 
1127
  p = oss_history_p;
 
1128
  oss_history_p = (oss_history_p + 1) % OSS_HISTORY_SIZE;
 
1129
 
 
1130
  tmp = oss_history[p];
 
1131
  memset (tmp, 0, OSS_HISTORY_STRSIZE);
 
1132
  s = tmp;
 
1133
 
 
1134
  sprintf (s, "%s.%02d: ", adev->devnode, adev->engine_num);
 
1135
  s += strlen (s);
 
1136
 
 
1137
  if (adev->pid != -1)
 
1138
    {
 
1139
      sprintf (s, "pid %d ", adev->pid);
 
1140
      s += strlen (s);
 
1141
    }
 
1142
 
 
1143
  if (*adev->cmd != 0)
 
1144
    {
 
1145
      sprintf (s, "cmd '%s' ", adev->cmd);
 
1146
      s += strlen (s);
 
1147
    }
 
1148
  else
 
1149
    {
 
1150
      strcpy (s, "cmd: Unknown ");
 
1151
      s += strlen (s);
 
1152
    }
 
1153
 
 
1154
  if (adev->open_mode & OPEN_READ)
 
1155
    {
 
1156
      sprintf (s, "IN ");
 
1157
      s += strlen (s);
 
1158
    }
 
1159
 
 
1160
  if (adev->open_mode & OPEN_WRITE)
 
1161
    {
 
1162
      sprintf (s, "OUT ");
 
1163
      s += strlen (s);
 
1164
    }
 
1165
 
 
1166
  if (adev->timeout_count > 0)
 
1167
    {
 
1168
      sprintf (s, "%d timeouts ", adev->timeout_count);
 
1169
      s += strlen (s);
 
1170
    }
 
1171
 
 
1172
  if (adev->dmap_out->play_underruns > 0)
 
1173
    {
 
1174
      sprintf (s, "%d underruns ", adev->dmap_out->play_underruns);
 
1175
      s += strlen (s);
 
1176
    }
 
1177
 
 
1178
  if (adev->dmap_in->rec_overruns > 0)
 
1179
    {
 
1180
      sprintf (s, "%d overruns ", adev->dmap_in->rec_overruns);
 
1181
      s += strlen (s);
 
1182
    }
 
1183
 
 
1184
  if (adev->dmap_out->num_errors > 0)
 
1185
    {
 
1186
      report_errors (s, "Play events:", adev, adev->dmap_out,
 
1187
                     OSS_HISTORY_STRSIZE - strlen (tmp) - 1);
 
1188
      s += strlen (s);
 
1189
      *s++ = ' ';
 
1190
    }
 
1191
 
 
1192
  if (adev->dmap_in->num_errors > 0)
 
1193
    {
 
1194
      report_errors (s, "Rec events:", adev, adev->dmap_in,
 
1195
                     OSS_HISTORY_STRSIZE - strlen (tmp) - 1);
 
1196
      s += strlen (s);
 
1197
      *s++ = ' ';
 
1198
    }
 
1199
}
 
1200
 
 
1201
char *
 
1202
audio_show_latency (int dev)
 
1203
{
 
1204
  static char str[32];
 
1205
  adev_p adev = audio_engines[dev];
 
1206
  dmap_p dmap;
 
1207
  int dr, fs;
 
1208
 
 
1209
  *str = 0;
 
1210
 
 
1211
  if (dev < 0 || dev >= num_audio_engines)
 
1212
    return "Bad device";
 
1213
 
 
1214
  if (adev->open_mode == 0)
 
1215
    return "Not opened";
 
1216
 
 
1217
  if (adev->open_mode == OPEN_READ)
 
1218
    dmap = adev->dmap_in;
 
1219
  else
 
1220
    dmap = adev->dmap_out;
 
1221
 
 
1222
  if (dmap == NULL)
 
1223
    return "Unknown";
 
1224
 
 
1225
  if (!(dmap->flags & DMAP_STARTED))
 
1226
    return "Not started";
 
1227
 
 
1228
  dr = dmap->data_rate;
 
1229
  fs = dmap->fragment_size;
 
1230
 
 
1231
  if (dr <= 0)
 
1232
    sprintf (str, "%d", dmap->fragment_size);
 
1233
  else
 
1234
    {
 
1235
      int r = (fs * 10000) / dr;
 
1236
 
 
1237
      sprintf (str, "%d/%d (%d.%d msec)", dmap->fragment_size, dr, r / 10,
 
1238
               r % 10);
 
1239
    }
 
1240
 
 
1241
 
 
1242
  return str;
 
1243
}
 
1244
 
 
1245
void
 
1246
oss_audio_release (int dev, struct fileinfo *file)
 
1247
{
 
1248
  adev_p adev;
 
1249
  int mode;
 
1250
  oss_native_word flags;
 
1251
 
 
1252
  sync_seed++;
 
1253
 
 
1254
  if (dev < 0 || dev >= num_audio_engines)
 
1255
    return;
 
1256
  if (file)
 
1257
    mode = file->mode & O_ACCMODE;
 
1258
  else
 
1259
    mode = OPEN_READ | OPEN_WRITE;
 
1260
#ifdef DO_TIMINGS
 
1261
    oss_timing_printf ("=-=-=- Closing audio engine %d -=-=-=", dev);
 
1262
#endif
 
1263
 
 
1264
  adev = audio_engines[dev];
 
1265
 
 
1266
  if (adev->unloaded || !adev->enabled)
 
1267
    {
 
1268
      cmn_err (CE_CONT, "Audio device %s not available - close aborted\n",
 
1269
               adev->name);
 
1270
      return;
 
1271
    }
 
1272
 
 
1273
  oss_audio_post (adev);
 
1274
  oss_audio_sync (adev);
 
1275
 
 
1276
#ifdef CONFIG_OSSD
 
1277
  ossd_event (adev->engine_num, OSSD_EV_CLOSE);
 
1278
#endif
 
1279
  adev->d->adrv_halt_io (dev);
 
1280
  adev->d->adrv_close (dev, mode);
 
1281
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
1282
  if (adev->dmask & DMASK_OUT)
 
1283
    {
 
1284
      adev->dmap_out->audio_callback = NULL;
 
1285
      if (!adev->dmap_out->buffer_protected)
 
1286
        if (adev->dmap_out->dmabuf != NULL)
 
1287
          memset (adev->dmap_out->dmabuf, adev->dmap_out->neutral_byte,
 
1288
                  adev->dmap_out->buffsize);
 
1289
    }
 
1290
 
 
1291
  if (adev->dmask & DMASK_IN)
 
1292
    {
 
1293
      adev->dmap_in->audio_callback = NULL;
 
1294
    }
 
1295
 
 
1296
  store_history (dev);
 
1297
 
 
1298
  memset (audio_engines[dev]->cmd, 0, sizeof (audio_engines[dev]->cmd));
 
1299
  memset (audio_engines[dev]->label, 0, sizeof (audio_engines[dev]->label));
 
1300
  memset (audio_engines[dev]->song_name, 0,
 
1301
          sizeof (audio_engines[dev]->song_name));
 
1302
  audio_engines[dev]->pid = -1;
 
1303
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
1304
 
 
1305
  /*
 
1306
   * Free the DMA buffer(s)
 
1307
   */
 
1308
  if (adev->dmask & DMASK_OUT)
 
1309
    if (adev->dmap_out->dmabuf != NULL)
 
1310
      {
 
1311
        if (adev->d->adrv_free_buffer != NULL)
 
1312
          {
 
1313
            adev->d->adrv_free_buffer (dev, adev->dmap_out, OPEN_WRITE);
 
1314
          }
 
1315
        else
 
1316
          default_free_buffer (dev, adev->dmap_out, OPEN_WRITE);
 
1317
        adev->dmap_out->dmabuf = NULL;
 
1318
      }
 
1319
 
 
1320
  if (adev->dmask & DMASK_IN)
 
1321
    if (adev->dmap_in != adev->dmap_out && adev->dmap_in->dmabuf != NULL)
 
1322
      {
 
1323
        if (adev->d->adrv_free_buffer != NULL)
 
1324
          {
 
1325
            adev->d->adrv_free_buffer (dev, adev->dmap_in, OPEN_READ);
 
1326
          }
 
1327
        else
 
1328
          default_free_buffer (dev, adev->dmap_in, OPEN_READ);
 
1329
        adev->dmap_in->dmabuf = NULL;
 
1330
      }
 
1331
 
 
1332
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
1333
  adev->open_mode = 0;
 
1334
  adev->flags &= ~ADEV_OPENED;
 
1335
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
1336
}
 
1337
 
 
1338
static void audio_outputintr (int dev, int intr_flags);
 
1339
static void audio_inputintr (int dev, int intr_flags);
 
1340
 
 
1341
/*ARGSUSED*/
 
1342
int
 
1343
oss_audio_open_engine (int dev, int no_worries, struct fileinfo *file,
 
1344
                       int recursive, int open_flags, int *newdev)
 
1345
{
 
1346
/*
 
1347
 * Open audio engine
 
1348
 */
 
1349
  adev_p adev;
 
1350
  int retval = 0, fmt;
 
1351
  int mode;
 
1352
  int saved_cooked;
 
1353
  int channels, rate;
 
1354
  oss_native_word flags;
 
1355
  extern int cooked_enable;     /* Config option */
 
1356
 
 
1357
  DOWN_STATUS (0xff);
 
1358
 
 
1359
  if (file)
 
1360
    {
 
1361
      mode = file->mode & O_ACCMODE;
 
1362
    }
 
1363
  else
 
1364
    mode = OPEN_READ | OPEN_WRITE;
 
1365
 
 
1366
  sync_seed++;
 
1367
 
 
1368
  DDB (cmn_err
 
1369
       (CE_CONT, "oss_audio_open_engine(%d, mode=0x%x)\n", dev, mode));
 
1370
 
 
1371
#ifdef DO_TIMINGS
 
1372
    oss_timing_printf ("-----> oss_audio_open_engine(%d, mode=0x%x)", dev, mode);
 
1373
#endif
 
1374
 
 
1375
  if (dev < 0 || dev >= num_audio_engines || audio_engines == NULL)
 
1376
    return OSS_ENXIO;
 
1377
 
 
1378
  adev = audio_engines[dev];
 
1379
  if (adev->unloaded)
 
1380
    return OSS_ENODEV;
 
1381
  if (!adev->enabled)
 
1382
    return OSS_ENXIO;
 
1383
 
 
1384
  if (adev->osdev == NULL)
 
1385
    {
 
1386
      cmn_err (CE_WARN, "adev->osdev==NULL\n");
 
1387
      return OSS_EIO;
 
1388
    }
 
1389
 
 
1390
  open_flags = get_open_flags (mode, open_flags, file);
 
1391
 
 
1392
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
1393
  if (adev->open_mode != 0)
 
1394
    {
 
1395
      MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
1396
      return OSS_EBUSY;
 
1397
    }
 
1398
  adev->open_mode = mode;
 
1399
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
1400
 
 
1401
  adev->cooked_enable = cooked_enable;  /* This must be done before drv->open() */
 
1402
#ifdef DO_TIMINGS
 
1403
  if (adev->cooked_enable)
 
1404
    oss_do_timing ("Initial cooked mode ON");
 
1405
  else
 
1406
    oss_do_timing ("Initial cooked mode OFF");
 
1407
#endif
 
1408
 
 
1409
  adev->src_quality = src_quality;
 
1410
  if ((retval = adev->d->adrv_open (dev, mode, open_flags)) < 0)
 
1411
    {
 
1412
      adev->open_mode = 0;
 
1413
 
 
1414
      return retval;
 
1415
    }
 
1416
 
 
1417
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
1418
  adev->outputintr = audio_outputintr;
 
1419
  adev->inputintr = audio_inputintr;
 
1420
  adev->forced_nonblock = 0;
 
1421
  adev->setfragment_warned = 0;
 
1422
  adev->getispace_error_count = 0;
 
1423
  adev->sync_next = NULL;
 
1424
  adev->sync_group = 0;
 
1425
  adev->sync_flags = 0;
 
1426
  adev->open_flags = open_flags;
 
1427
  adev->flags |= ADEV_OPENED;
 
1428
  adev->timeout_count = 0;
 
1429
  adev->policy = -1;
 
1430
  adev->song_name[0] = 0;
 
1431
  adev->label[0] = 0;
 
1432
 
 
1433
  if (open_flags & (OF_NOCONV | OF_MMAP))
 
1434
    {
 
1435
      adev->cooked_enable = 0;
 
1436
#ifdef DO_TIMINGS
 
1437
      oss_do_timing ("Forcing cooked mode OFF");
 
1438
#endif
 
1439
    }
 
1440
 
 
1441
  memset (audio_engines[dev]->cmd, 0, sizeof (audio_engines[dev]->cmd));
 
1442
 
 
1443
  if (recursive)
 
1444
    {
 
1445
      strcpy (audio_engines[dev]->cmd, "OSS internal");
 
1446
      audio_engines[dev]->pid = 0;
 
1447
    }
 
1448
  else
 
1449
    {
 
1450
      char *cmd;
 
1451
 
 
1452
      if ((cmd = GET_PROCESS_NAME (file)) != NULL)
 
1453
        {
 
1454
          strncpy (audio_engines[dev]->cmd, cmd, 16);
 
1455
          strncpy (audio_engines[dev]->label, cmd, 16);
 
1456
          audio_engines[dev]->cmd[15] = '\0';
 
1457
          audio_engines[dev]->label[15] = '\0';
 
1458
        }
 
1459
      audio_engines[dev]->pid = GET_PROCESS_PID (file);
 
1460
    }
 
1461
 
 
1462
  adev->dmask = 0;
 
1463
/*
 
1464
 * Find out which dmap structures are required.
 
1465
 */
 
1466
 
 
1467
  if (mode == OPEN_WRITE)
 
1468
    adev->dmask = DMASK_OUT;
 
1469
  else if (mode == OPEN_READ)
 
1470
    adev->dmask = DMASK_IN;
 
1471
  else
 
1472
    {
 
1473
      if (mode != (OPEN_WRITE | OPEN_READ))
 
1474
        cmn_err (CE_NOTE, "Unrecognized open mode %x\n", mode);
 
1475
      adev->dmask = DMASK_OUT;
 
1476
 
 
1477
      if ((adev->flags & ADEV_DUPLEX) && adev->dmap_out != adev->dmap_in)
 
1478
        adev->dmask = DMASK_OUT | DMASK_IN;
 
1479
    }
 
1480
 
 
1481
#if 0
 
1482
/*
 
1483
 * Handling of non-blocking doesn't belong here. It will be handled
 
1484
 * by read/write.
 
1485
 */
 
1486
  if (file != NULL && !(open_flags & OF_BLOCK))
 
1487
    if (ISSET_FILE_FLAG (file, O_NONBLOCK) || adev->forced_nonblock)
 
1488
      {
 
1489
#ifdef DO_TIMINGS
 
1490
        oss_do_timing ("*** Non-blocking open ***");
 
1491
#endif
 
1492
        adev->nonblock = 1;
 
1493
      }
 
1494
#endif
 
1495
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
1496
 
 
1497
  if (adev->dmask & DMASK_OUT)
 
1498
    {
 
1499
 
 
1500
      /*
 
1501
       * Use small DMA buffer if requested and if the device supports it.
 
1502
       */
 
1503
      if (SMALL_DMABUF_SIZE >= (adev->min_block * 2) &&
 
1504
          (open_flags & OF_SMALLBUF))
 
1505
        adev->dmap_out->flags |= DMAP_SMALLBUF;
 
1506
      else
 
1507
        if (MEDIUM_DMABUF_SIZE >= (adev->min_block * 2) &&
 
1508
            (open_flags & OF_MEDIUMBUF))
 
1509
        adev->dmap_out->flags |= DMAP_MEDIUMBUF;
 
1510
      else
 
1511
        adev->dmap_out->flags &= ~(DMAP_SMALLBUF | DMAP_MEDIUMBUF);
 
1512
 
 
1513
      if ((retval = init_dmap (adev, adev->dmap_out, OPEN_WRITE)) < 0)
 
1514
        {
 
1515
          oss_audio_release (dev, file);
 
1516
          return retval;
 
1517
        }
 
1518
    }
 
1519
 
 
1520
  if (adev->dmask & DMASK_IN)
 
1521
    {
 
1522
      /*
 
1523
       * Use small DMA buffer if requested and if the device supports it.
 
1524
       */
 
1525
      if (SMALL_DMABUF_SIZE >= (adev->min_block * 2) &&
 
1526
          (open_flags & OF_SMALLBUF))
 
1527
        adev->dmap_in->flags |= DMAP_SMALLBUF;
 
1528
      else
 
1529
        adev->dmap_in->flags &= ~DMAP_SMALLBUF;
 
1530
 
 
1531
      if ((retval = init_dmap (adev, adev->dmap_in, OPEN_READ)) < 0)
 
1532
        {
 
1533
          oss_audio_release (dev, file);
 
1534
          return retval;
 
1535
        }
 
1536
    }
 
1537
 
 
1538
  adev->dmap_out->num_errors = 0;
 
1539
  adev->dmap_in->num_errors = 0;
 
1540
 
 
1541
  if ((mode & OPEN_WRITE) && !(adev->flags & ADEV_NOOUTPUT))
 
1542
    {
 
1543
      oss_reset_wait_queue (adev->out_wq);
 
1544
    }
 
1545
  if ((mode & OPEN_READ) && !(adev->flags & ADEV_NOINPUT))
 
1546
    {
 
1547
      oss_reset_wait_queue (adev->in_wq);
 
1548
    }
 
1549
 
 
1550
  adev->xformat_mask = 0;
 
1551
 
 
1552
  switch (adev->dmask)
 
1553
    {
 
1554
    case DMASK_OUT:
 
1555
      adev->xformat_mask = adev->oformat_mask;
 
1556
      break;
 
1557
 
 
1558
    case DMASK_IN:
 
1559
      adev->xformat_mask = adev->iformat_mask;
 
1560
      break;
 
1561
 
 
1562
    case DMASK_OUT | DMASK_IN:
 
1563
      adev->xformat_mask = adev->oformat_mask & adev->iformat_mask;
 
1564
      break;
 
1565
 
 
1566
    default:
 
1567
      cmn_err (CE_WARN, "Internal error A during open\n");
 
1568
    }
 
1569
 
 
1570
  fmt = DSP_DEFAULT_FMT;
 
1571
  rate = DSP_DEFAULT_SPEED;
 
1572
 
 
1573
  if (adev->flags & ADEV_FIXEDRATE && adev->fixed_rate != 0)
 
1574
    rate = adev->fixed_rate;
 
1575
 
 
1576
  if (adev->flags & ADEV_16BITONLY)
 
1577
    fmt = AFMT_S16_LE;
 
1578
 
 
1579
  adev->go = 1;
 
1580
  adev->enable_bits = adev->open_mode;
 
1581
 
 
1582
  channels = 1;
 
1583
  if (adev->flags & ADEV_STEREOONLY)
 
1584
    channels = 2;
 
1585
 
 
1586
  saved_cooked = adev->cooked_enable;
 
1587
  adev->cooked_enable = 0;
 
1588
  oss_audio_set_format (dev, fmt, adev->xformat_mask);
 
1589
  oss_audio_set_channels (dev, channels);
 
1590
  oss_audio_set_rate (dev, rate);
 
1591
  adev->cooked_enable = saved_cooked;
 
1592
 
 
1593
/* Clear the Cooked mode to permit mmap() */
 
1594
  if (adev->dmask & DMASK_OUT)
 
1595
    adev->dmap_out->flags &= ~DMAP_COOKED;
 
1596
  if (adev->dmask & DMASK_IN)
 
1597
    adev->dmap_in->flags &= ~DMAP_COOKED;
 
1598
 
 
1599
#ifdef DO_TIMINGS
 
1600
  {
 
1601
    char *p_name;
 
1602
    pid_t proc_pid;
 
1603
    oss_timing_printf ("=-=-=- Audio device %d (%s) opened, mode %x -=-=-=",
 
1604
             adev->engine_num, adev->name, mode);
 
1605
 
 
1606
    if ((proc_pid = GET_PROCESS_PID (file)) != -1)
 
1607
        oss_timing_printf ("Opened by PID: %d", proc_pid);
 
1608
 
 
1609
    if ((p_name = GET_PROCESS_NAME (file)) != NULL)
 
1610
        oss_timing_printf ("Opening process name: %s", p_name);
 
1611
  }
 
1612
#endif
 
1613
 
 
1614
#ifdef CONFIG_OSSD
 
1615
  ossd_event (adev->engine_num, OSSD_EV_OPEN);
 
1616
#endif
 
1617
 
 
1618
  return adev->engine_num;
 
1619
}
 
1620
 
 
1621
#ifdef VDEV_SUPPORT
 
1622
int
 
1623
oss_audio_open_devfile (int dev, int dev_class, struct fileinfo *file,
 
1624
                        int recursive, int open_flags, int *newdev)
 
1625
{
 
1626
/*
 
1627
 * Open audio device file (by calling oss_audio_open_engine).
 
1628
 */
 
1629
  int err, d, n;
 
1630
  int open_excl = 0;
 
1631
  adev_p adev;
 
1632
  int mode = OPEN_READ | OPEN_WRITE;
 
1633
 
 
1634
#ifdef DO_TIMINGS
 
1635
    oss_timing_printf ("-----> oss_audio_open_devfile(%d, mode=0x%x)", dev, mode);
 
1636
#endif
 
1637
 
 
1638
  if (file)
 
1639
    {
 
1640
      mode = file->mode & O_ACCMODE;
 
1641
      open_flags = get_open_flags (mode, open_flags, file);
 
1642
      if (file->acc_flags & O_EXCL)
 
1643
        {
 
1644
          if (excl_policy == 0) open_excl = 1;
 
1645
#ifdef GET_PROCESS_UID
 
1646
          else if ((excl_policy == 1) && (GET_PROCESS_UID () == 0)) open_excl = 1;
 
1647
#endif
 
1648
        }
 
1649
    }
 
1650
 
 
1651
  DDB (cmn_err
 
1652
       (CE_CONT, "oss_audio_open_devfile(%d, mode=0x%x, excl=%d)\n", dev,
 
1653
        mode, open_excl));
 
1654
 
 
1655
  if (dev < 0 || dev >= num_audio_devfiles)
 
1656
    {
 
1657
      return OSS_ENODEV;
 
1658
    }
 
1659
  adev = audio_devfiles[dev];
 
1660
  dev = adev->engine_num;
 
1661
 
 
1662
  n=0;
 
1663
  while (adev->d->adrv_redirect != NULL)
 
1664
     {
 
1665
             int next_dev = dev;
 
1666
 
 
1667
             if (n++ > num_audio_engines)
 
1668
                {
 
1669
                        cmn_err(CE_CONT, "Recursive audio device redirection\n");
 
1670
                        return OSS_ELOOP;
 
1671
                }
 
1672
 
 
1673
             next_dev = adev->d->adrv_redirect (dev, mode, open_flags);
 
1674
#ifdef DO_TIMINGS
 
1675
             oss_timing_printf ("Engine redirect %d -> %d\n", dev, next_dev);
 
1676
#endif
 
1677
 
 
1678
             if (next_dev == dev) /* No change */
 
1679
                break;
 
1680
 
 
1681
             if (next_dev < 0 || next_dev >= num_audio_engines)
 
1682
                return OSS_ENXIO;
 
1683
 
 
1684
             dev = next_dev;
 
1685
             adev = audio_engines[dev];
 
1686
     }
 
1687
 
 
1688
/*
 
1689
 * Check Exclusive mode open - do not do any kind of device
 
1690
 * sharing. For the time being this mode is not supported with devices
 
1691
 * that do hardware mixing.
 
1692
 */
 
1693
  if (open_excl && !(adev->flags & ADEV_HWMIX))
 
1694
    {
 
1695
      DDB (cmn_err
 
1696
           (CE_CONT, "Exclusive open, engine=%d\n", adev->engine_num));
 
1697
      if ((dev = oss_audio_open_engine (adev->engine_num, dev_class, file,
 
1698
                                        recursive, open_flags, newdev)) < 0)
 
1699
        {
 
1700
          return dev;
 
1701
        }
 
1702
 
 
1703
      goto done;
 
1704
    }
 
1705
  
 
1706
#ifdef CONFIG_OSS_VMIX
 
1707
/*
 
1708
 * Get a vmix engine if the device has vmix support enabled.
 
1709
 */
 
1710
  if (!vmix_disabled)
 
1711
  if (adev->vmix_mixer != NULL) // Virtual mixer attached
 
1712
     {
 
1713
             int vmix_dev;
 
1714
 
 
1715
             /*
 
1716
              * Create a new vmix client instance.
 
1717
              */
 
1718
 
 
1719
             if ((vmix_dev=vmix_create_client(adev->vmix_mixer))>=0)
 
1720
                {
 
1721
#ifdef DO_TIMINGS
 
1722
             oss_timing_printf ("Vmix redirect %d -> %d\n", dev, vmix_dev);
 
1723
#endif
 
1724
                      if ((dev = oss_audio_open_engine (vmix_dev, dev_class, file,
 
1725
                                                        recursive, open_flags, newdev)) < 0)
 
1726
                        {
 
1727
                          //cmn_err(CE_WARN, "Failed to open vmix engine %d, err=%d\n", vmix_dev, dev);
 
1728
                          return dev;
 
1729
                        }
 
1730
#ifdef DO_TIMINGS
 
1731
             oss_timing_printf ("Vmix engine opened %d -> %d\n", vmix_dev, dev);
 
1732
#endif
 
1733
                
 
1734
                      goto done;
 
1735
                }
 
1736
     }
 
1737
#endif
 
1738
 
 
1739
#if 0
 
1740
/*
 
1741
 * Follow redirection chain for the device.
 
1742
 *
 
1743
 * (TODO: This feature was for earlier versions of vmix/softoss and not in use for the time being. However
 
1744
 * it is possible that some other driver finds use for it in the future).
 
1745
 */
 
1746
 
 
1747
  if (!open_excl)
 
1748
     {
 
1749
          if (mode == OPEN_WRITE)
 
1750
            {
 
1751
              redirect = adev->redirect_out;
 
1752
            }
 
1753
          else if (mode == OPEN_READ)
 
1754
            {
 
1755
              redirect = adev->redirect_in;
 
1756
            }
 
1757
          else
 
1758
            {
 
1759
              /*
 
1760
               * Read-write open. Check that redirection for both directions are
 
1761
               * identical.
 
1762
               */
 
1763
              if (adev->redirect_out == adev->redirect_in)
 
1764
                redirect = adev->redirect_out;
 
1765
            }
 
1766
     }
 
1767
  DDB (cmn_err
 
1768
       (CE_CONT, "Redirect=%d (%d, %d)\n", redirect, adev->redirect_out,
 
1769
        adev->redirect_in));
 
1770
 
 
1771
  if (redirect >= 0 && redirect < num_audio_engines)
 
1772
    {
 
1773
      adev = audio_engines[redirect];
 
1774
      DDB (cmn_err
 
1775
           (CE_CONT, "Redirect devfile %d -> engine=%d\n", dev,
 
1776
            adev->engine_num));
 
1777
      dev = redirect;
 
1778
    }
 
1779
#endif
 
1780
 
 
1781
  while (adev != NULL)
 
1782
    {
 
1783
      DDB (cmn_err (CE_CONT, "Trying engine=%d\n", adev->engine_num));
 
1784
      if (!adev->enabled)
 
1785
        return OSS_EAGAIN;
 
1786
 
 
1787
      if (adev->unloaded)
 
1788
        return OSS_EAGAIN;
 
1789
 
 
1790
      *newdev = adev->engine_num;
 
1791
      if ((err =
 
1792
           oss_audio_open_engine (adev->engine_num, dev_class, file,
 
1793
                                  recursive, open_flags, newdev)) < 0)
 
1794
        {
 
1795
          /* 
 
1796
           * Check if the device was busy and if it has a
 
1797
           * shadow device.
 
1798
           */
 
1799
          if (err != OSS_EBUSY || adev->next_out == NULL)
 
1800
            return err;
 
1801
          adev = adev->next_out;
 
1802
        }
 
1803
      else
 
1804
        {
 
1805
          dev = adev->engine_num;
 
1806
          DDB (cmn_err (CE_CONT, "Engine %d opened\n", adev->engine_num));
 
1807
          goto done;
 
1808
        }
 
1809
    }
 
1810
 
 
1811
  return OSS_EBUSY;
 
1812
 
 
1813
done:
 
1814
/*
 
1815
 * Try to find which minor number matches this /dev/dsp# device.
 
1816
 */
 
1817
 
 
1818
  if ((d = oss_find_minor (OSS_DEV_DSP_ENGINE, dev)) < 0)
 
1819
    {
 
1820
      oss_audio_release (dev, file);
 
1821
      return d;
 
1822
    }
 
1823
 
 
1824
  *newdev = d;
 
1825
  return dev;
 
1826
}
 
1827
#endif
 
1828
 
 
1829
static struct
 
1830
{
 
1831
  int sz, nfrags;
 
1832
} policies[] =
 
1833
{
 
1834
  {
 
1835
  8, 2},                        /* 0 */
 
1836
  {
 
1837
  16, 2},                       /* 1 */
 
1838
  {
 
1839
  128, 2},                      /* 2 */
 
1840
  {
 
1841
  256, 4},                      /* 3 */
 
1842
  {
 
1843
  512, 4},                      /* 4 */
 
1844
  {
 
1845
  1024, 0},                     /* 5 */
 
1846
  {
 
1847
  2048, 0},                     /* 6 */
 
1848
  {
 
1849
  4096, 0},                     /* 7 */
 
1850
  {
 
1851
  16384, 0},                    /* 8 */
 
1852
  {
 
1853
  32768, 0},                    /* 9 */
 
1854
  {
 
1855
  256 *1024, 0},                /* 10 */
 
1856
};
 
1857
 
 
1858
static void
 
1859
setup_fragments (adev_p adev, dmap_p dmap, int direction)
 
1860
{
 
1861
  int sz, maxfrags = 100000;
 
1862
  int min;
 
1863
  extern int max_intrate;
 
1864
 
 
1865
  if (adev->max_intrate == 0 || adev->max_intrate > max_intrate)
 
1866
    adev->max_intrate = max_intrate;
 
1867
 
 
1868
  if (dmap->flags & DMAP_FRAGFIXED)
 
1869
    return;
 
1870
  dmap->flags |= DMAP_FRAGFIXED;
 
1871
 
 
1872
#ifdef DO_TIMINGS
 
1873
    oss_timing_printf ("setup_fragments(%d, dir=%d)", adev->engine_num, direction);
 
1874
#endif
 
1875
 
 
1876
  sz = 1024;
 
1877
 
 
1878
  dmap->low_water_rq = 0;
 
1879
  dmap->low_water = -1;
 
1880
 
 
1881
  if (dmap->fragsize_rq != 0)   /* SNDCTL_DSP_SETFRAGMENT was called */
 
1882
    {
 
1883
      int v;
 
1884
      v = dmap->fragsize_rq & 0xffff;
 
1885
 
 
1886
      sz = (1 << v);
 
1887
 
 
1888
      if (dmap->expand_factor != UNIT_EXPAND)
 
1889
        {
 
1890
          int sz2;
 
1891
 
 
1892
          sz2 = (sz * dmap->expand_factor) / UNIT_EXPAND;
 
1893
 
 
1894
          if (sz < sz2)
 
1895
            {
 
1896
              while (sz < sz2)
 
1897
                sz *= 2;
 
1898
            }
 
1899
          else if (sz > sz2)
 
1900
            {
 
1901
              while (sz > sz2)
 
1902
                sz /= 2;
 
1903
            }
 
1904
 
 
1905
        }
 
1906
 
 
1907
      if (sz < 8)
 
1908
        sz = 8;
 
1909
      if (sz > dmap->buffsize / 2)
 
1910
        sz = dmap->buffsize / 2;
 
1911
 
 
1912
      maxfrags = (dmap->fragsize_rq >> 16) & 0x7fff;
 
1913
 
 
1914
      if (maxfrags == 0)
 
1915
        maxfrags = 0x7fff;
 
1916
      else if (maxfrags < 2)
 
1917
        maxfrags = 2;
 
1918
 
 
1919
      if (maxfrags < adev->min_fragments)
 
1920
        maxfrags = adev->min_fragments;
 
1921
      else if (adev->max_fragments >= 2 && maxfrags > adev->max_fragments)
 
1922
        maxfrags = adev->max_fragments;
 
1923
 
 
1924
#if 1
 
1925
      /*
 
1926
       * Workaround for realplay
 
1927
       */
 
1928
      if (adev->open_flags & OF_SMALLFRAGS)
 
1929
        while (sz > dmap->buffsize / 8)
 
1930
          {
 
1931
            maxfrags *= 2;
 
1932
            sz /= 2;
 
1933
          }
 
1934
#endif
 
1935
    }
 
1936
 
 
1937
  if (adev->policy >= 0 && adev->policy <= 10)
 
1938
    {
 
1939
      sz = policies[adev->policy].sz;
 
1940
      maxfrags = policies[adev->policy].nfrags;
 
1941
      if (maxfrags == 0)        /* Unlimited */
 
1942
        maxfrags = 0xffff;
 
1943
    }
 
1944
 
 
1945
#if 1
 
1946
  /* Use short fragments if ossd has registered this device */
 
1947
  if (adev->ossd_registered)
 
1948
    sz = 256;
 
1949
#endif
 
1950
 
 
1951
  /* Sanity check */
 
1952
  if (adev->min_block && adev->max_block)
 
1953
    if (adev->min_block > adev->max_block)
 
1954
      adev->min_block = adev->max_block = 0;
 
1955
 
 
1956
  if (adev->max_block > 0 && sz > adev->max_block)
 
1957
    sz = adev->max_block;
 
1958
  if (adev->min_block > 0 && sz < adev->min_block)
 
1959
    sz = adev->min_block;
 
1960
 
 
1961
  if (sz < 8)
 
1962
    sz = 8;
 
1963
 
 
1964
  /* Ensure that the interrupt rate is within the limits */
 
1965
 
 
1966
  min = 0;
 
1967
 
 
1968
  if (adev->max_intrate > 0)
 
1969
    {
 
1970
      int data_rate;
 
1971
 
 
1972
      data_rate = dmap->data_rate;
 
1973
      if (data_rate < 8000)
 
1974
        data_rate = adev->hw_parms.rate * 4;
 
1975
 
 
1976
      min = data_rate / adev->max_intrate;
 
1977
 
 
1978
      if (min > dmap->buffsize / 2)
 
1979
        min = dmap->buffsize / 2;
 
1980
#ifdef DO_TIMINGS
 
1981
        oss_timing_printf ("Max intrate %d -> min buffer %d", adev->max_intrate,
 
1982
                 min);
 
1983
#endif
 
1984
    }
 
1985
 
 
1986
#if 1
 
1987
  if (dmap->flags & DMAP_COOKED)
 
1988
    if (min < 256)
 
1989
      min = 256;
 
1990
#endif
 
1991
 
 
1992
  if (adev->max_block && min > adev->max_block)
 
1993
    min = adev->max_block;
 
1994
 
 
1995
  if (sz < min)
 
1996
    {
 
1997
      while (sz < min)
 
1998
        sz *= 2;
 
1999
      if (adev->max_block > 0 && sz > adev->max_block)
 
2000
        sz = adev->max_block;
 
2001
    }
 
2002
 
 
2003
  dmap->fragment_size = sz;
 
2004
  dmap->nfrags = dmap->buffsize / sz;
 
2005
 
 
2006
  if (dmap == adev->dmap_out)
 
2007
    {
 
2008
      if (direction == OPEN_WRITE)
 
2009
        {
 
2010
          if (dmap->nfrags > maxfrags)
 
2011
            dmap->nfrags = maxfrags;
 
2012
        }
 
2013
    }
 
2014
 
 
2015
  if (adev->d->adrv_setup_fragments)
 
2016
    {
 
2017
      adev->d->adrv_setup_fragments (adev->engine_num, dmap, direction);
 
2018
    }
 
2019
 
 
2020
  dmap->bytes_in_use = dmap->nfrags * dmap->fragment_size;
 
2021
 
 
2022
  if (dmap->nfrags < 2)
 
2023
    {
 
2024
      dmap->nfrags = 2;
 
2025
      dmap->fragment_size = dmap->bytes_in_use / 2;
 
2026
    }
 
2027
 
 
2028
  while (dmap->nfrags < adev->min_fragments)
 
2029
    {
 
2030
      dmap->nfrags *= 2;
 
2031
      dmap->fragment_size /= 2;
 
2032
    }
 
2033
 
 
2034
  if (adev->max_fragments >= 2)
 
2035
    while (dmap->nfrags > adev->max_fragments)
 
2036
      {
 
2037
        dmap->nfrags /= 2;
 
2038
        dmap->fragment_size *= 2;
 
2039
      }
 
2040
  while (dmap->nfrags < adev->min_fragments)
 
2041
    {
 
2042
      dmap->nfrags *= 2;
 
2043
      dmap->fragment_size /= 2;
 
2044
    }
 
2045
 
 
2046
  dmap->bytes_in_use = dmap->nfrags * dmap->fragment_size;
 
2047
 
 
2048
  dmap->bytes_in_use = dmap->nfrags * dmap->fragment_size;
 
2049
  dmap->low_water_rq = dmap->fragment_size;
 
2050
 
 
2051
#if 1
 
2052
  if (dmap->nfrags < 4)
 
2053
#endif
 
2054
    if (dmap->low_water_rq < dmap->bytes_in_use / 4)
 
2055
      dmap->low_water_rq = dmap->bytes_in_use / 4;
 
2056
 
 
2057
#ifdef DO_TIMINGS
 
2058
    oss_timing_printf ("fragsz=%d, nfrags=%d", dmap->fragment_size, dmap->nfrags);
 
2059
#endif
 
2060
}
 
2061
 
 
2062
static int
 
2063
getblksize (adev_p adev)
 
2064
{
 
2065
  int size = 4096;
 
2066
  dmap_p dmap;
 
2067
  oss_native_word flags, dflags;
 
2068
  dflags = 0;
 
2069
 
 
2070
  MUTEX_ENTER_IRQDISABLE (adev->mutex, flags);
 
2071
  if (adev->dmask & DMASK_IN)
 
2072
    {
 
2073
      dmap = adev->dmap_in;
 
2074
 
 
2075
      if (!(dmap->flags & DMAP_FRAGFIXED))
 
2076
        {
 
2077
          MUTEX_ENTER (dmap->mutex, dflags);
 
2078
          setup_fragments (adev, dmap, OPEN_READ);
 
2079
          size = dmap->fragment_size;
 
2080
          MUTEX_EXIT (dmap->mutex, dflags);
 
2081
        }
 
2082
    }
 
2083
 
 
2084
  if (adev->dmask & DMASK_OUT)
 
2085
    {
 
2086
      dmap = adev->dmap_out;
 
2087
 
 
2088
      if (!(dmap->flags & DMAP_FRAGFIXED))
 
2089
        {
 
2090
          MUTEX_ENTER (dmap->mutex, dflags);
 
2091
          setup_fragments (adev, dmap, OPEN_WRITE);
 
2092
          size = dmap->fragment_size;
 
2093
          MUTEX_EXIT (dmap->mutex, dflags);
 
2094
        }
 
2095
    }
 
2096
  MUTEX_EXIT_IRQRESTORE (adev->mutex, flags);
 
2097
 
 
2098
  return size;
 
2099
}
 
2100
 
 
2101
/*ARGSUSED*/
 
2102
static oss_uint64_t
 
2103
get_output_pointer (adev_p adev, dmap_p dmap, int do_adjust)
 
2104
{
 
2105
  oss_uint64_t ptr;
 
2106
 
 
2107
  if (adev->d->adrv_get_output_pointer == NULL)
 
2108
    {
 
2109
      return dmap->fragment_counter * dmap->fragment_size;
 
2110
    }
 
2111
 
 
2112
  UP_STATUS (STS_PTR);
 
2113
  ptr =
 
2114
    adev->d->adrv_get_output_pointer (adev->engine_num, dmap,
 
2115
                                      PCM_ENABLE_OUTPUT) & ~7;
 
2116
  DOWN_STATUS (STS_PTR);
 
2117
 
 
2118
  return ptr;
 
2119
}
 
2120
 
 
2121
static oss_uint64_t
 
2122
get_input_pointer (adev_p adev, dmap_p dmap, int do_adjust)
 
2123
{
 
2124
  oss_uint64_t ptr;
 
2125
 
 
2126
  if (adev->d->adrv_get_input_pointer == NULL)
 
2127
    return dmap->fragment_counter * dmap->fragment_size;
 
2128
 
 
2129
  ptr =
 
2130
    adev->d->adrv_get_input_pointer (adev->engine_num, dmap,
 
2131
                                     PCM_ENABLE_INPUT) & ~7;
 
2132
  if (ptr < dmap->byte_counter)
 
2133
    ptr += dmap->bytes_in_use;
 
2134
  ptr %= dmap->bytes_in_use;
 
2135
 
 
2136
  if (do_adjust)
 
2137
    {
 
2138
      oss_uint64_t tmp = dmap->byte_counter;
 
2139
 
 
2140
      tmp = (tmp / dmap->bytes_in_use) * dmap->bytes_in_use;
 
2141
      dmap->byte_counter = tmp + ptr;
 
2142
    }
 
2143
 
 
2144
  return ptr;
 
2145
}
 
2146
 
 
2147
static int
 
2148
get_optr (adev_p adev, dmap_p dmap, ioctl_arg arg)
 
2149
{
 
2150
  count_info *info = (count_info *) arg;
 
2151
  oss_native_word flags;
 
2152
  oss_uint64_t bytes;
 
2153
 
 
2154
  memset ((char *) info, 0, sizeof (count_info));
 
2155
 
 
2156
  if (dmap->dma_mode != PCM_ENABLE_OUTPUT || !(dmap->flags & DMAP_STARTED))
 
2157
    return 0;
 
2158
 
 
2159
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
2160
 
 
2161
  info->ptr = get_output_pointer (adev, dmap, 1);
 
2162
  info->blocks = dmap->interrupt_count;
 
2163
  dmap->interrupt_count = 0;
 
2164
 
 
2165
  bytes = (dmap->byte_counter / dmap->bytes_in_use) * dmap->bytes_in_use;
 
2166
  bytes += info->ptr;
 
2167
  if (bytes < dmap->byte_counter)
 
2168
    bytes += dmap->bytes_in_use;
 
2169
  info->bytes = (unsigned int) bytes;
 
2170
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2171
 
 
2172
  /* Adjust for format conversions */
 
2173
  info->ptr = (info->ptr * UNIT_EXPAND) / dmap->expand_factor;
 
2174
  info->bytes = (info->bytes / dmap->expand_factor) * UNIT_EXPAND;
 
2175
  info->bytes &= 0x3fffffff;
 
2176
 
 
2177
#ifdef DO_TIMINGS
 
2178
    oss_timing_printf ("GETOPTR(%d,%d,%d)", info->bytes, info->ptr, info->blocks);
 
2179
#endif
 
2180
  return 0;
 
2181
}
 
2182
 
 
2183
static int
 
2184
get_iptr (adev_p adev, dmap_p dmap, ioctl_arg arg)
 
2185
{
 
2186
  count_info *info = (count_info *) arg;
 
2187
  oss_native_word flags;
 
2188
  oss_uint64_t bytes;
 
2189
 
 
2190
  memset ((char *) info, 0, sizeof (count_info));
 
2191
 
 
2192
  if (dmap->dma_mode != PCM_ENABLE_INPUT || !(dmap->flags & DMAP_STARTED))
 
2193
    return 0;
 
2194
 
 
2195
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
2196
  info->ptr = get_input_pointer (adev, dmap, 1);
 
2197
  info->blocks = dmap->interrupt_count;
 
2198
  dmap->interrupt_count = 0;
 
2199
 
 
2200
  bytes = (dmap->byte_counter / dmap->bytes_in_use) * dmap->bytes_in_use;
 
2201
  bytes += info->ptr;
 
2202
  if (bytes < dmap->byte_counter)
 
2203
    bytes += dmap->bytes_in_use;
 
2204
  info->bytes = (unsigned int) bytes;
 
2205
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2206
 
 
2207
  /* Adjust for format conversions */
 
2208
  info->ptr = (info->ptr * UNIT_EXPAND) / dmap->expand_factor;
 
2209
  info->bytes = (info->bytes / dmap->expand_factor) * UNIT_EXPAND;
 
2210
  info->bytes &= 0x3fffffff;
 
2211
 
 
2212
#ifdef DO_TIMINGS
 
2213
    oss_timing_printf ("GETIPTR(%d,%d,%d)", info->bytes, info->ptr, info->blocks);
 
2214
#endif
 
2215
  return 0;
 
2216
}
 
2217
 
 
2218
#ifndef OSS_NO_LONG_LONG
 
2219
static int
 
2220
get_long_optr (adev_p adev, dmap_p dmap, ioctl_arg arg)
 
2221
{
 
2222
  oss_count_t *ptr = (oss_count_t *) arg;
 
2223
  oss_native_word flags;
 
2224
  oss_uint64_t pos, bytes;
 
2225
 
 
2226
  memset ((char *) ptr, 0, sizeof (*ptr));
 
2227
 
 
2228
  if (dmap->dma_mode != PCM_ENABLE_OUTPUT || !(dmap->flags & DMAP_STARTED))
 
2229
    return 0;
 
2230
 
 
2231
  ptr->fifo_samples = 0;
 
2232
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
2233
  if (dmap->frame_size < 1)
 
2234
    dmap->frame_size = 1;
 
2235
  if (dmap->user_frame_size < 1)
 
2236
    dmap->user_frame_size = 1;
 
2237
  pos = get_output_pointer (adev, dmap, 1);
 
2238
  bytes = (dmap->byte_counter / dmap->bytes_in_use) * dmap->bytes_in_use;
 
2239
  bytes += pos;
 
2240
  ptr->samples = (unsigned int) (bytes / dmap->frame_size);
 
2241
 
 
2242
  /* Adjust for format conversions */
 
2243
  ptr->samples = (ptr->samples * UNIT_EXPAND) / dmap->expand_factor;
 
2244
 
 
2245
  if (adev->d->adrv_local_qlen)
 
2246
    {
 
2247
      ptr->fifo_samples =
 
2248
        adev->d->adrv_local_qlen (adev->engine_num) / dmap->frame_size;
 
2249
      ptr->fifo_samples =
 
2250
        (ptr->fifo_samples * UNIT_EXPAND) / dmap->expand_factor;
 
2251
    }
 
2252
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2253
 
 
2254
  return 0;
 
2255
}
 
2256
 
 
2257
static int
 
2258
get_long_iptr (adev_p adev, dmap_p dmap, ioctl_arg arg)
 
2259
{
 
2260
  oss_count_t *ptr = (oss_count_t *) arg;
 
2261
  oss_native_word flags;
 
2262
  oss_uint64_t pos, bytes;
 
2263
 
 
2264
  memset ((char *) ptr, 0, sizeof (*ptr));
 
2265
 
 
2266
  if (dmap->dma_mode != PCM_ENABLE_INPUT || !(dmap->flags & DMAP_STARTED))
 
2267
    return 0;
 
2268
 
 
2269
  ptr->fifo_samples = 0;
 
2270
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
2271
  if (dmap->frame_size < 1)
 
2272
    dmap->frame_size = 1;
 
2273
  if (dmap->user_frame_size < 1)
 
2274
    dmap->user_frame_size = 1;
 
2275
  pos = get_input_pointer (adev, dmap, 1);
 
2276
  bytes = (dmap->byte_counter / dmap->bytes_in_use) * dmap->bytes_in_use;
 
2277
  bytes += pos;
 
2278
  ptr->samples = (unsigned int) (bytes / dmap->frame_size);
 
2279
 
 
2280
  /* Adjust for format conversions */
 
2281
  ptr->samples = (ptr->samples / dmap->expand_factor) * UNIT_EXPAND;
 
2282
 
 
2283
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2284
 
 
2285
  return 0;
 
2286
}
 
2287
#endif
 
2288
 
 
2289
static int
 
2290
get_odelay (adev_p adev, dmap_p dmap, ioctl_arg arg)
 
2291
{
 
2292
  oss_int64_t val, pos;
 
2293
  oss_native_word flags;
 
2294
  if (dmap->dma_mode != PCM_ENABLE_OUTPUT ||
 
2295
      (dmap->mapping_flags & DMA_MAP_MAPPED))
 
2296
    return *arg = (0);
 
2297
 
 
2298
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
2299
  pos = get_output_pointer (adev, dmap, 1);
 
2300
  val = (dmap->byte_counter / dmap->bytes_in_use) * dmap->bytes_in_use;
 
2301
  val += pos;
 
2302
  val = dmap->user_counter - val;
 
2303
  if (val < 0)
 
2304
    val = 0;
 
2305
  if (val > dmap->bytes_in_use)
 
2306
    val = dmap->bytes_in_use;
 
2307
 
 
2308
  if (adev->d->adrv_local_qlen)
 
2309
    {
 
2310
      val += adev->d->adrv_local_qlen (adev->engine_num);
 
2311
    }
 
2312
 
 
2313
  val += dmap->leftover_bytes;
 
2314
  val = (val * UNIT_EXPAND) / dmap->expand_factor;
 
2315
 
 
2316
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2317
#ifdef DO_TIMINGS
 
2318
    oss_timing_printf ("GETODELAY(%d, %d)", adev->engine_num, val);
 
2319
#endif
 
2320
  return *arg = (val);
 
2321
}
 
2322
 
 
2323
static int audio_space_in_queue (adev_p adev, dmap_p dmap, int count);
 
2324
 
 
2325
static int
 
2326
get_ospace (adev_p adev, dmap_p dmap, ioctl_arg arg)
 
2327
{
 
2328
  audio_buf_info *info = (audio_buf_info *) arg;
 
2329
  oss_native_word flags;
 
2330
 
 
2331
  memset ((char *) info, 0, sizeof (audio_buf_info));
 
2332
 
 
2333
  if (!(dmap->flags & DMAP_PREPARED))
 
2334
    {
 
2335
      setup_fragments (adev, dmap, OPEN_WRITE);
 
2336
      prepare_output (adev, dmap);
 
2337
    }
 
2338
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
2339
  info->fragstotal = dmap->nfrags;
 
2340
 
 
2341
  info->fragsize = (dmap->fragment_size * UNIT_EXPAND) / dmap->expand_factor;
 
2342
 
 
2343
  /* Make sure we report full samples */
 
2344
  info->fragsize =
 
2345
    ((info->fragsize + dmap->user_frame_size -
 
2346
      1) / dmap->user_frame_size) * dmap->user_frame_size;
 
2347
 
 
2348
  if (!(adev->open_mode & OPEN_WRITE))
 
2349
    {
 
2350
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2351
      cmn_err (CE_WARN,
 
2352
               "SNDCTL_DSP_GETOSPACE cannot be called in read-only mode.\n");
 
2353
#ifdef DO_TIMINGS
 
2354
      oss_do_timing ("GETOSPACE: Bad access mode - return EACCES");
 
2355
#endif
 
2356
      return OSS_EACCES;
 
2357
    }
 
2358
 
 
2359
  if (dmap->mapping_flags & DMA_MAP_MAPPED)
 
2360
    {
 
2361
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2362
      cmn_err (CE_WARN,
 
2363
               "SNDCTL_DSP_GETOSPACE cannot be called in mmap mode.\n");
 
2364
#ifdef DO_TIMINGS
 
2365
      oss_do_timing ("GETOSPACE: mmap access mode - return EPERM");
 
2366
#endif
 
2367
      oss_audio_set_error (adev->engine_num, E_PLAY,
 
2368
                           OSSERR (1000, "GETOSPACE called in mmap mode"), 0);
 
2369
      /* Errordesc:
 
2370
       * Do not call SNDCTL_DSP_GETOSPACE in mmap mode. Use SNDCTL_DSP_GETOPTR
 
2371
       * instead. SNDCTL_DSP_GETOSPACE is defined only for applications that
 
2372
       * use the normal write() method.
 
2373
       * Applications that use mmap can call SNDCTL_DSP_GETOSPACE before calling
 
2374
       * mmap to get the actual buffer size.
 
2375
       */
 
2376
      return OSS_EPERM;
 
2377
    }
 
2378
 
 
2379
  if (!(dmap->flags & DMAP_STARTED))
 
2380
    {
 
2381
      int bytes;
 
2382
      bytes = (int) ((long long) dmap->bytes_in_use - dmap->user_counter);
 
2383
#ifdef DO_TIMINGS
 
2384
      {
 
2385
        oss_do_timing ("GETOSPACE: Not started - ignore device count");
 
2386
        oss_timing_printf ("bytes_in_use=%d", dmap->bytes_in_use);
 
2387
        oss_timing_printf ("user_counter=%lld", dmap->user_counter);
 
2388
        oss_timing_printf ("raw bytes=%d", bytes);
 
2389
      }
 
2390
#endif
 
2391
      bytes = (bytes / dmap->expand_factor) * UNIT_EXPAND;      /* Round downwards */
 
2392
      bytes = (bytes / dmap->user_frame_size) * dmap->user_frame_size;  /* Truncate to frame size */
 
2393
      info->bytes = bytes;
 
2394
      info->fragments = info->fragstotal = dmap->nfrags;
 
2395
      if (info->bytes > info->fragsize * info->fragstotal)
 
2396
        info->bytes = info->fragsize * info->fragstotal;
 
2397
 
 
2398
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2399
      return 0;
 
2400
    }
 
2401
 
 
2402
  info->bytes = audio_space_in_queue (adev, dmap, 0);
 
2403
#ifdef DO_TIMINGS
 
2404
    oss_timing_printf ("audio_space_in_queue returned %d", info->bytes);
 
2405
#endif
 
2406
 
 
2407
  if (info->bytes < dmap->low_water)
 
2408
    info->bytes = 0;
 
2409
 
 
2410
  if (adev->dmap_out->flags & DMAP_COOKED)
 
2411
    {
 
2412
 
 
2413
      if (dmap->tmpbuf_ptr > 0)
 
2414
        info->bytes -= dmap->tmpbuf_ptr;
 
2415
    }
 
2416
 
 
2417
  if ((adev->dmap_out->flags & DMAP_COOKED) && info->bytes <
 
2418
      dmap->fragment_size / 2)
 
2419
    {
 
2420
#ifdef DO_TIMINGS
 
2421
      oss_do_timing ("GETOSPACE: Buffer full");
 
2422
#endif
 
2423
      info->bytes = 0;
 
2424
    }
 
2425
 
 
2426
  if (info->bytes < 0)
 
2427
    info->bytes = 0;
 
2428
 
 
2429
  info->bytes = (info->bytes * UNIT_EXPAND) / dmap->expand_factor;
 
2430
  info->bytes = (info->bytes / dmap->user_frame_size) * dmap->user_frame_size;  /* Truncate to frame size */
 
2431
  if (dmap->flags & DMAP_COOKED)
 
2432
    {
 
2433
      /*
 
2434
       * Reserve some space for format conversions. Sample rate conversions
 
2435
       * may not always be able to take the "last" sample with fractional conversion
 
2436
       * ratios.
 
2437
       */
 
2438
      if (info->bytes >= dmap->frame_size)
 
2439
        info->bytes -= dmap->frame_size;        /* Substract one sample. */
 
2440
    }
 
2441
  info->fragments = info->bytes / info->fragsize;
 
2442
 
 
2443
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2444
 
 
2445
  if (info->bytes > info->fragsize * info->fragstotal)
 
2446
    info->bytes = info->fragsize * info->fragstotal;
 
2447
 
 
2448
  return 0;
 
2449
}
 
2450
 
 
2451
static int
 
2452
get_ispace (adev_p adev, dmap_p dmap, ioctl_arg arg)
 
2453
{
 
2454
  audio_buf_info *info = (audio_buf_info *) arg;
 
2455
  oss_native_word flags;
 
2456
 
 
2457
  memset ((char *) info, 0, sizeof (audio_buf_info));
 
2458
 
 
2459
  setup_fragments (adev, dmap, OPEN_READ);
 
2460
  prepare_input (adev, dmap);
 
2461
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
2462
  info->fragstotal = dmap->nfrags;
 
2463
  info->fragsize = (dmap->fragment_size * UNIT_EXPAND) / dmap->expand_factor;
 
2464
 
 
2465
  /* Make sure we report full samples */
 
2466
  info->fragsize =
 
2467
    ((info->fragsize + dmap->user_frame_size -
 
2468
      1) / dmap->user_frame_size) * dmap->user_frame_size;
 
2469
 
 
2470
  if (!(adev->open_mode & OPEN_READ))
 
2471
    {
 
2472
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2473
      cmn_err (CE_WARN,
 
2474
               "SNDCTL_DSP_GETISPACE cannot be called in write-only mode.\n");
 
2475
      return OSS_EACCES;
 
2476
    }
 
2477
 
 
2478
  if (dmap->mapping_flags & DMA_MAP_MAPPED)
 
2479
    {
 
2480
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2481
      cmn_err (CE_WARN,
 
2482
               "SNDCTL_DSP_GETISPACE cannot be called in mmap mode.\n");
 
2483
      oss_audio_set_error (adev->engine_num, E_REC,
 
2484
                           OSSERR (1003, "GETISPACE called in mmap mode"), 0);
 
2485
      /* Errordesc:
 
2486
       * Do not call SNDCTL_DSP_GETISPACE in mmap mode.
 
2487
       * SNDCTL_DSP_GETISPACE is defined only for applications that
 
2488
       * use the normal write() method.
 
2489
       * Applications that use mmap can call SNDCTL_DSP_GETISPACE before calling
 
2490
       * mmap to get the actual buffer size.
 
2491
       */
 
2492
      return OSS_EPERM;
 
2493
    }
 
2494
 
 
2495
  if (!(dmap->flags & DMAP_STARTED))
 
2496
    {
 
2497
/*
 
2498
 * A stupid application has called GETISPACE before recording has started.
 
2499
 * The right behaviour would definitely be returning bytes=0. However
 
2500
 * reporting one ready fragment will keep poor programmers happy.
 
2501
 * After all this is a minor error because no properly written application
 
2502
 * should ever call GETISPACE before starting recording.
 
2503
 */
 
2504
      info->bytes = info->fragsize;
 
2505
      info->fragments = 1;
 
2506
 
 
2507
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2508
      if (info->bytes > info->fragsize * info->fragstotal)
 
2509
        info->bytes = info->fragsize * info->fragstotal;
 
2510
      if (adev->getispace_error_count++ == 1)   /* Second time this happens */
 
2511
        {
 
2512
          oss_audio_set_error (adev->engine_num, E_REC,
 
2513
                               OSSERR (1004,
 
2514
                                       "GETISPACE called before recording has been started"),
 
2515
                               0);
 
2516
          /*
 
2517
           * Errordesc:
 
2518
           * There is no recoded data available before recording has been started.
 
2519
           * This would result in situation where the application waits infinitely
 
2520
           * for recorded data that never arrives. As a workaround 
 
2521
           * SNDCTL_DSP_GETISPACE will fake that one fragment is already available
 
2522
           * to read. This in turn makes the application to block incorrectly.
 
2523
           *
 
2524
           * Applications must start recording before calling SNDCTL_DSP_GETISPACE
 
2525
           * if they are trying to avoid blocking. This can be done by calling
 
2526
           * SNDCTL_DSP_SETTRIGGER.
 
2527
           *
 
2528
           * However applications going to use mmap can/should call
 
2529
           * SNDCTL_DSP_GETISPACE in the beginning to find out how large buffer to
 
2530
           * map. In such case this event is a false alarm.
 
2531
           */
 
2532
        }
 
2533
      return 0;
 
2534
    }
 
2535
 
 
2536
  info->bytes = (unsigned int) (dmap->byte_counter - dmap->user_counter);
 
2537
 
 
2538
  if (dmap->flags & DMAP_COOKED)
 
2539
    {
 
2540
      /* Count the already converted bytes in the tmp buffer */
 
2541
      int nn = dmap->tmpbuf_len - dmap->tmpbuf_ptr;
 
2542
 
 
2543
      if (nn > 0)
 
2544
        info->bytes += nn;
 
2545
    }
 
2546
 
 
2547
  if (info->bytes > dmap->bytes_in_use)
 
2548
    info->bytes = dmap->bytes_in_use;
 
2549
 
 
2550
  info->bytes = (info->bytes * UNIT_EXPAND) / dmap->expand_factor;
 
2551
  info->bytes = (info->bytes / dmap->user_frame_size) * dmap->user_frame_size;
 
2552
  info->fragments = info->bytes / info->fragsize;
 
2553
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
2554
 
 
2555
  if (info->bytes > info->fragsize * info->fragstotal)
 
2556
    info->bytes = info->fragsize * info->fragstotal;
 
2557
 
 
2558
#ifdef DO_TIMINGS
 
2559
    oss_timing_printf ("GETISPACE(%d,%d,%d,%d)", info->bytes, info->fragments,
 
2560
             info->fragsize, info->fragstotal);
 
2561
#endif
 
2562
  return 0;
 
2563
}
 
2564
 
 
2565
#define xrand(seed) (seed=1664525*seed+1013904223)
 
2566
 
 
2567
static void
 
2568
setfragment_error (int dev)
 
2569
{
 
2570
  if (audio_engines[dev]->setfragment_warned)
 
2571
    return;
 
2572
 
 
2573
  oss_audio_set_error (dev, E_PLAY,
 
2574
                       OSSERR (1011,
 
2575
                               "SNDCTL_DSP_SETFRAGMENT was called too late."),
 
2576
                       0);
 
2577
  /*
 
2578
   * Errordesc: The SNDCTL_DSP_SETFRAGMENT call is only valid immediately after
 
2579
   * opening the device. It can only be called once without reopening
 
2580
   * the audio device. 
 
2581
   *
 
2582
   * Calling read/write or certain ioctl calls will lock the fragment size/count
 
2583
   * to some values which makes changing it impossible.
 
2584
   */
 
2585
 
 
2586
#ifdef DO_TIMINGS
 
2587
  oss_do_timing ("Setfragment called twice");
 
2588
#endif
 
2589
 
 
2590
  audio_engines[dev]->setfragment_warned = 1;
 
2591
}
 
2592
 
 
2593
static int
 
2594
handle_syncgroup (adev_p adev, oss_syncgroup * group)
 
2595
{
 
2596
  int id, sync_dev;
 
2597
  adev_p sync_adev;
 
2598
 
 
2599
  if (adev->sync_group != 0)
 
2600
    {
 
2601
      return OSS_EBUSY;
 
2602
    }
 
2603
 
 
2604
  if (group->id == 0)
 
2605
    {
 
2606
      if (adev->engine_num > SYNC_DEVICE_MASK)
 
2607
        {
 
2608
          cmn_err (CE_WARN, "Bad device number %d\n", adev->engine_num);
 
2609
          return OSS_EIO;
 
2610
        }
 
2611
 
 
2612
      id = xrand (sync_seed) & ~SYNC_DEVICE_MASK; /* Clear the engine number field */
 
2613
      id |= adev->engine_num;
 
2614
 
 
2615
      group->id = id;
 
2616
      sync_dev = adev->engine_num;
 
2617
      adev->sync_next = NULL;
 
2618
    }
 
2619
  else
 
2620
    {
 
2621
      id = group->id;
 
2622
      sync_dev = id & SYNC_DEVICE_MASK;
 
2623
    }
 
2624
 
 
2625
  if (sync_dev < 0 || sync_dev >= num_audio_engines)
 
2626
    {
 
2627
      group->id = 0;
 
2628
      return OSS_EINVAL;
 
2629
    }
 
2630
 
 
2631
  sync_adev = audio_engines[sync_dev];
 
2632
 
 
2633
  if (sync_dev == adev->engine_num)
 
2634
    adev->sync_flags |= SYNC_MASTER;
 
2635
  else
 
2636
    {
 
2637
      if (!(sync_adev->sync_flags & SYNC_MASTER))
 
2638
        {
 
2639
          return OSS_EINVAL;
 
2640
        }
 
2641
 
 
2642
      if (sync_adev->sync_group != id)
 
2643
        {
 
2644
          return OSS_EINVAL;
 
2645
        }
 
2646
 
 
2647
      adev->sync_flags |= SYNC_SLAVE;
 
2648
    }
 
2649
 
 
2650
  group->mode &= (PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT);
 
2651
  group->mode &= adev->open_mode;
 
2652
  if (group->mode == 0)
 
2653
    {
 
2654
      adev->sync_flags = 0;
 
2655
      return OSS_EINVAL;
 
2656
    }
 
2657
 
 
2658
  adev->sync_mode = group->mode;
 
2659
  adev->sync_group = id;
 
2660
  if (adev->d->adrv_sync_control != NULL)
 
2661
    adev->d->adrv_sync_control (adev->engine_num, SYNC_ATTACH,
 
2662
                                adev->sync_mode);
 
2663
 
 
2664
  if (adev != sync_adev)
 
2665
    {
 
2666
      adev->sync_next = sync_adev->sync_next;
 
2667
      sync_adev->sync_next = adev;
 
2668
    }
 
2669
 
 
2670
  adev->go = 0;
 
2671
 
 
2672
  return 0;
 
2673
}
 
2674
 
 
2675
static int
 
2676
handle_syncstart (int orig_dev, int group)
 
2677
{
 
2678
  int master_dev, arg;
 
2679
  adev_p adev, next;
 
2680
 
 
2681
  master_dev = group & SYNC_DEVICE_MASK;
 
2682
  if (master_dev < 0 || master_dev >= num_audio_engines)
 
2683
    return OSS_EINVAL;
 
2684
 
 
2685
  adev = audio_engines[master_dev];
 
2686
 
 
2687
  if (!(adev->sync_flags & SYNC_MASTER) ||
 
2688
     master_dev != orig_dev)
 
2689
     {
 
2690
        /*
 
2691
         * Potential attack. SYNCSTART was called on wrong file descriptor.
 
2692
         */
 
2693
        return OSS_EPERM;
 
2694
     }
 
2695
 
 
2696
  if (adev->sync_group != group)
 
2697
    return OSS_EINVAL;
 
2698
 
 
2699
/*
 
2700
 * Pass 1: Inform all devices about the actual start command to come soon.
 
2701
 */
 
2702
 
 
2703
  while (adev != NULL)
 
2704
    {
 
2705
 
 
2706
      if (adev->sync_group == group)
 
2707
        {
 
2708
          adev->go = 0;
 
2709
 
 
2710
          if (adev->d->adrv_sync_control)
 
2711
            {
 
2712
              if (adev->sync_mode & PCM_ENABLE_INPUT)
 
2713
                {
 
2714
                  if (!(adev->dmap_in->flags & DMAP_PREPARED))
 
2715
                    {
 
2716
                      adev->dmap_in->dma_mode = PCM_ENABLE_INPUT;
 
2717
                      prepare_input (adev, adev->dmap_in);
 
2718
                    }
 
2719
                  launch_input (adev, adev->dmap_in);
 
2720
                }
 
2721
              if (adev->sync_mode & PCM_ENABLE_OUTPUT)
 
2722
                {
 
2723
                  dmap_p dmap = adev->dmap_out;
 
2724
                  int err;
 
2725
 
 
2726
                  if (adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)
 
2727
                    dmap->dma_mode = PCM_ENABLE_OUTPUT;
 
2728
                  if ((err = prepare_output (adev, adev->dmap_out)) < 0)
 
2729
                    return err;
 
2730
                  launch_output (adev, adev->dmap_out);
 
2731
                }
 
2732
              adev->d->adrv_sync_control (adev->engine_num, SYNC_PREPARE,
 
2733
                                          adev->sync_mode);
 
2734
            }
 
2735
          else
 
2736
            {
 
2737
              arg = 0;
 
2738
              oss_audio_ioctl (adev->engine_num, NULL, SNDCTL_DSP_SETTRIGGER,
 
2739
                               (ioctl_arg) & arg);
 
2740
            }
 
2741
        }
 
2742
      else
 
2743
        {
 
2744
          cmn_err (CE_NOTE, "Broken sync chain\n");
 
2745
        }
 
2746
 
 
2747
      adev = adev->sync_next;
 
2748
    }
 
2749
 
 
2750
/*
 
2751
 * Pass 2: Deliver the actual start commands.
 
2752
 */
 
2753
 
 
2754
  adev = audio_engines[master_dev];
 
2755
 
 
2756
  while (adev != NULL)
 
2757
    {
 
2758
 
 
2759
      if (adev->sync_group == group)
 
2760
        {
 
2761
          adev->go = 1;
 
2762
 
 
2763
          if (adev->d->adrv_sync_control)
 
2764
            adev->d->adrv_sync_control (adev->engine_num, SYNC_TRIGGER,
 
2765
                                        adev->sync_mode);
 
2766
          else
 
2767
            {
 
2768
              arg = adev->sync_mode;
 
2769
              oss_audio_ioctl (adev->engine_num, NULL, SNDCTL_DSP_SETTRIGGER,
 
2770
                               (ioctl_arg) & arg);
 
2771
            }
 
2772
        }
 
2773
      else
 
2774
        {
 
2775
          /* Skip this one */
 
2776
          adev = adev->sync_next;
 
2777
          continue;
 
2778
        }
 
2779
 
 
2780
      next = adev->sync_next;
 
2781
      adev->sync_next = NULL;
 
2782
      adev->sync_flags = 0;
 
2783
      adev->sync_group = 0;
 
2784
 
 
2785
      adev = next;
 
2786
    }
 
2787
  return 0;
 
2788
}
 
2789
 
 
2790
#ifdef DO_TIMINGS
 
2791
static char *
 
2792
find_ioctl_name (unsigned int cmd, ioctl_arg val)
 
2793
{
 
2794
  static char tmp[32];
 
2795
 
 
2796
  typedef struct
 
2797
  {
 
2798
    unsigned int code;
 
2799
    char *name;
 
2800
    int flags;
 
2801
#define IOF_DEC         0x00000001
 
2802
#define IOF_HEX         0x00000002
 
2803
  } ioctl_def_t;
 
2804
 
 
2805
  static ioctl_def_t call_names[] = {
 
2806
    {SNDCTL_DSP_HALT, "SNDCTL_DSP_HALT"},
 
2807
    {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
 
2808
    {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED", IOF_DEC},
 
2809
    {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO", IOF_DEC},
 
2810
    {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
 
2811
    {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS", IOF_DEC},
 
2812
    {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
 
2813
    {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
 
2814
    {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT", IOF_HEX},
 
2815
    {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
 
2816
    {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT", IOF_HEX},
 
2817
    {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
 
2818
    {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
 
2819
    {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
 
2820
    {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
 
2821
    {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER", IOF_HEX},
 
2822
    {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
 
2823
    {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
 
2824
    {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO", IOF_HEX},
 
2825
    {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
 
2826
    {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
 
2827
    {SNDCTL_DSP_GETPLAYVOL, "SNDCTL_DSP_GETPLAYVOL"},
 
2828
    {SNDCTL_DSP_SETPLAYVOL, "SNDCTL_DSP_SETPLAYVOL", IOF_HEX},
 
2829
    {SNDCTL_DSP_GETRECVOL, "SNDCTL_DSP_GETRECVOL"},
 
2830
    {SNDCTL_DSP_SETRECVOL, "SNDCTL_DSP_SETRECVOL", IOF_HEX},
 
2831
    {SNDCTL_DSP_GETERROR, "SNDCTL_DSP_GETERROR"},
 
2832
    {SNDCTL_DSP_READCTL, "SNDCTL_DSP_READCTL"},
 
2833
    {SNDCTL_DSP_WRITECTL, "SNDCTL_DSP_WRITECTL"},
 
2834
    {SNDCTL_DSP_SYNCGROUP, "SNDCTL_DSP_SYNCGROUP"},
 
2835
    {SNDCTL_DSP_SYNCSTART, "SNDCTL_DSP_SYNCSTART"},
 
2836
    {SNDCTL_DSP_COOKEDMODE, "SNDCTL_DSP_COOKEDMODE", IOF_DEC},
 
2837
    {SNDCTL_DSP_SILENCE, "SNDCTL_DSP_SILENCE"},
 
2838
    {SNDCTL_DSP_SKIP, "SNDCTL_DSP_SKIP"},
 
2839
    {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
 
2840
    {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
 
2841
    {SNDCTL_DSP_HALT_INPUT, "SNDCTL_DSP_HALT_INPUT"},
 
2842
    {SNDCTL_DSP_HALT_OUTPUT, "SNDCTL_DSP_HALT_OUTPUT"},
 
2843
    {SNDCTL_DSP_LOW_WATER, "SNDCTL_DSP_LOW_WATER"},
 
2844
#ifndef OSS_NO_LONG_LONG
 
2845
    {SNDCTL_DSP_CURRENT_IPTR, "SNDCTL_DSP_CURRENT_IPTR"},
 
2846
    {SNDCTL_DSP_CURRENT_OPTR, "SNDCTL_DSP_CURRENT_OPTR"},
 
2847
#endif
 
2848
    {SNDCTL_DSP_GET_RECSRC, "SNDCTL_DSP_GET_RECSRC"},
 
2849
    {SNDCTL_DSP_SET_RECSRC, "SNDCTL_DSP_SET_RECSRC"},
 
2850
    {SNDCTL_DSP_GET_RECSRC_NAMES, "SNDCTL_DSP_GET_RECSRC_NAMES"},
 
2851
    {SNDCTL_DSP_GET_PLAYTGT, "SNDCTL_DSP_GET_PLAYTGT"},
 
2852
    {SNDCTL_DSP_SET_PLAYTGT, "SNDCTL_DSP_SET_PLAYTGT"},
 
2853
    {SNDCTL_DSP_GET_PLAYTGT_NAMES, "SNDCTL_DSP_GET_PLAYTGT_NAMES"},
 
2854
    {0, NULL}
 
2855
  };
 
2856
 
 
2857
  int i;
 
2858
  for (i = 0; call_names[i].code != 0; i++)
 
2859
    if (call_names[i].code == cmd)
 
2860
      {
 
2861
        int flags = call_names[i].flags;
 
2862
 
 
2863
        if (flags & IOF_DEC)
 
2864
          {
 
2865
            sprintf (tmp, "%s,  *%d", call_names[i].name, *val);
 
2866
            return tmp;
 
2867
          }
 
2868
 
 
2869
        if (flags & IOF_HEX)
 
2870
          {
 
2871
            sprintf (tmp, "%s, *0x%08x", call_names[i].name, *val);
 
2872
            return tmp;
 
2873
          }
 
2874
 
 
2875
        return call_names[i].name;
 
2876
      }
 
2877
 
 
2878
  sprintf (tmp, "Unknown %08x", cmd);
 
2879
  return tmp;
 
2880
}
 
2881
#endif
 
2882
 
 
2883
/*ARGSUSED*/
 
2884
int
 
2885
oss_encode_enum (oss_mixer_enuminfo * ei, const char *s, int version)
 
2886
{
 
2887
  int n = 1, l;
 
2888
  int i;
 
2889
 
 
2890
  memset (ei, 0, sizeof (*ei)); /* Wipe out everything */
 
2891
 
 
2892
  strncpy (ei->strings, s, sizeof (ei->strings) - 1);
 
2893
  ei->strings[sizeof (ei->strings) - 1] = 0;
 
2894
 
 
2895
  ei->strindex[0] = 0;
 
2896
 
 
2897
  l = strlen (ei->strings);
 
2898
  for (i = 0; i < l; i++)
 
2899
    {
 
2900
      if (ei->strings[i] == ' ')
 
2901
        {
 
2902
          ei->strindex[n++] = i + 1;
 
2903
          ei->strings[i] = 0;
 
2904
        }
 
2905
    }
 
2906
 
 
2907
  ei->nvalues = n;
 
2908
 
 
2909
  return 0;
 
2910
}
 
2911
 
 
2912
static int
 
2913
get_legacy_recsrc_names (int dev, oss_mixer_enuminfo * ei)
 
2914
{
 
2915
  static const char *labels[] = SOUND_DEVICE_NAMES;
 
2916
 
 
2917
  int i, mixer_dev, recmask, devmask, caps, n;
 
2918
  char *s;
 
2919
 
 
2920
  if (audio_engines[dev]->mixer_dev < 0)        /* No mixer */
 
2921
    return 0;
 
2922
 
 
2923
  mixer_dev = audio_engines[dev]->mixer_dev;
 
2924
 
 
2925
 
 
2926
  if (oss_legacy_mixer_ioctl
 
2927
      (mixer_dev, -1, SOUND_MIXER_READ_CAPS, (ioctl_arg) & caps) < 0)
 
2928
    caps = 0;                   /* Error */
 
2929
 
 
2930
  if (caps & SOUND_CAP_NORECSRC)
 
2931
    return 0;
 
2932
 
 
2933
  if (oss_legacy_mixer_ioctl
 
2934
      (mixer_dev, -1, SOUND_MIXER_READ_DEVMASK, (ioctl_arg) & devmask) < 0)
 
2935
    return 0;                   /* Error */
 
2936
 
 
2937
  if (oss_legacy_mixer_ioctl
 
2938
      (mixer_dev, -1, SOUND_MIXER_READ_RECMASK, (ioctl_arg) & recmask) < 0)
 
2939
    return 0;                   /* Error */
 
2940
 
 
2941
  recmask &= devmask;
 
2942
  if (recmask == 0)
 
2943
    return 0;
 
2944
 
 
2945
  n = 0;
 
2946
  s = ei->strings;
 
2947
 
 
2948
  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 
2949
    if (recmask & (1 << i))     /* This control is also recording device */
 
2950
      {
 
2951
         /*LINTED*/ ei->strindex[n] = s - ei->strings;
 
2952
 
 
2953
        strcpy (s, labels[i]);
 
2954
        s += strlen (s);
 
2955
        *s++ = 0;
 
2956
        n++;
 
2957
      }
 
2958
 
 
2959
  ei->nvalues = n;
 
2960
 
 
2961
  return (n > 0);
 
2962
}
 
2963
 
 
2964
static int
 
2965
get_legacy_recsrc (int dev)
 
2966
{
 
2967
  int i, mixer_dev, recmask, recsrc, caps, n;
 
2968
 
 
2969
  if (audio_engines[dev]->mixer_dev < 0)        /* No mixer */
 
2970
    return 0;
 
2971
 
 
2972
  mixer_dev = audio_engines[dev]->mixer_dev;
 
2973
 
 
2974
 
 
2975
  if (oss_legacy_mixer_ioctl
 
2976
      (mixer_dev, -1, SOUND_MIXER_READ_CAPS, (ioctl_arg) & caps) < 0)
 
2977
    caps = 0;                   /* Error */
 
2978
 
 
2979
  if (caps & SOUND_CAP_NORECSRC)
 
2980
    return 0;
 
2981
 
 
2982
  if (oss_legacy_mixer_ioctl
 
2983
      (mixer_dev, -1, SOUND_MIXER_READ_RECSRC, (ioctl_arg) & recsrc) < 0)
 
2984
    return 0;                   /* Error */
 
2985
 
 
2986
  if (oss_legacy_mixer_ioctl
 
2987
      (mixer_dev, -1, SOUND_MIXER_READ_RECMASK, (ioctl_arg) & recmask) < 0)
 
2988
    return 0;                   /* Error */
 
2989
 
 
2990
  if (recmask == 0 || recsrc == 0)
 
2991
    return 0;
 
2992
 
 
2993
  n = 0;
 
2994
 
 
2995
  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 
2996
    if (recmask & (1 << i))     /* This control is also recording device */
 
2997
      {
 
2998
        if (recsrc & (1 << i))  /* It was this one */
 
2999
          return n;
 
3000
        n++;
 
3001
      }
 
3002
 
 
3003
 
 
3004
  return 0;
 
3005
}
 
3006
 
 
3007
static int
 
3008
set_legacy_recsrc (int dev, int val)
 
3009
{
 
3010
  int i, mixer_dev, recmask, recsrc, caps, n;
 
3011
 
 
3012
  if (audio_engines[dev]->mixer_dev < 0)        /* No mixer */
 
3013
    return 0;
 
3014
 
 
3015
  mixer_dev = audio_engines[dev]->mixer_dev;
 
3016
 
 
3017
 
 
3018
  if (oss_legacy_mixer_ioctl
 
3019
      (mixer_dev, -1, SOUND_MIXER_READ_CAPS, (ioctl_arg) & caps) < 0)
 
3020
    caps = 0;                   /* Error */
 
3021
 
 
3022
  if (caps & SOUND_CAP_NORECSRC)
 
3023
    return 0;
 
3024
 
 
3025
  if (oss_legacy_mixer_ioctl
 
3026
      (mixer_dev, -1, SOUND_MIXER_READ_RECMASK, (ioctl_arg) & recmask) < 0)
 
3027
    return 0;                   /* Error */
 
3028
 
 
3029
  if (recmask == 0)
 
3030
    return 0;
 
3031
 
 
3032
  n = 0;
 
3033
 
 
3034
  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 
3035
    if (recmask & (1 << i))     /* This control is also recording device */
 
3036
      {
 
3037
        if (n == val)
 
3038
          {
 
3039
            recsrc = (1 << i);
 
3040
 
 
3041
            if (oss_legacy_mixer_ioctl
 
3042
                (mixer_dev, -1, SOUND_MIXER_WRITE_RECSRC,
 
3043
                 (ioctl_arg) & recsrc) < 0)
 
3044
              return 0;         /* Error */
 
3045
 
 
3046
            return 1;
 
3047
          }
 
3048
        n++;
 
3049
      }
 
3050
 
 
3051
 
 
3052
  return 0;
 
3053
}
 
3054
 
 
3055
/*ARGSUSED*/
 
3056
int
 
3057
oss_audio_ioctl (int dev, struct fileinfo *bogus,
 
3058
                 unsigned int cmd, ioctl_arg arg)
 
3059
{
 
3060
  int val, err;
 
3061
  int mixdev;
 
3062
  int ret;
 
3063
  adev_p adev;
 
3064
  dmap_p dmapin, dmapout;
 
3065
  oss_native_word flags;
 
3066
#ifdef DO_TIMINGS
 
3067
  oss_timing_printf ("oss_audio_ioctl(%d, %s)", dev, find_ioctl_name (cmd, arg));
 
3068
#endif
 
3069
 
 
3070
  if (cmd == OSS_GETVERSION)
 
3071
    return *arg = OSS_VERSION;
 
3072
 
 
3073
  UP_STATUS (STS_IOCTL);
 
3074
  DOWN_STATUS (STS_IOCTL);
 
3075
  sync_seed++;
 
3076
 
 
3077
  if (dev < 0 || dev >= num_audio_engines)
 
3078
    return OSS_ENXIO;
 
3079
 
 
3080
  adev = audio_engines[dev];
 
3081
  if (adev->unloaded)
 
3082
    return OSS_ENODEV;
 
3083
  if (!adev->enabled)
 
3084
    return OSS_ENXIO;
 
3085
 
 
3086
  if (adev->d->adrv_ioctl_override != NULL)
 
3087
  {
 
3088
  /*
 
3089
   * Use the ioctl override function if available. However process the request
 
3090
   * in the usual way if the override function returned OSS_EAGAIN. It may
 
3091
   * be possible that the override function has modified the parameters
 
3092
   * before returning.
 
3093
   */
 
3094
          if ((err = adev->d->adrv_ioctl_override(dev, cmd, arg)) != OSS_EAGAIN)
 
3095
             return err;
 
3096
  }
 
3097
 
 
3098
  dmapout = adev->dmap_out;
 
3099
  dmapin = adev->dmap_in;
 
3100
 
 
3101
/*
 
3102
 * Handle mixer ioctl calls on audio fd.
 
3103
 */
 
3104
 
 
3105
  if (cmd == SOUND_MIXER_WRITE_PCM) cmd = SNDCTL_DSP_SETPLAYVOL;
 
3106
  if (cmd == SOUND_MIXER_WRITE_RECLEV) cmd = SNDCTL_DSP_SETRECVOL;
 
3107
  if (cmd == SOUND_MIXER_READ_PCM) cmd = SNDCTL_DSP_GETPLAYVOL;
 
3108
  if (cmd == SOUND_MIXER_READ_RECLEV) cmd = SNDCTL_DSP_GETRECVOL;
 
3109
 
 
3110
  if ((mixdev = adev->mixer_dev) != -1)
 
3111
    {
 
3112
      if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */
 
3113
        if ((ret = oss_legacy_mixer_ioctl (mixdev, dev, cmd, arg)) != OSS_EINVAL)
 
3114
          return ret;
 
3115
    }
 
3116
 
 
3117
  if (((cmd >> 8) & 0xff) == 'X')       /* Mixer extension API */
 
3118
     return oss_mixer_ext (adev->engine_num, OSS_DEV_DSP, cmd, arg);
 
3119
 
 
3120
  switch (cmd)
 
3121
    {
 
3122
    case SNDCTL_DSP_SYNC:
 
3123
      oss_audio_sync (adev);
 
3124
      return 0;
 
3125
      break;
 
3126
 
 
3127
    case SNDCTL_DSP_POST:
 
3128
      oss_audio_post (adev);
 
3129
      return 0;
 
3130
      break;
 
3131
 
 
3132
    case SNDCTL_DSP_HALT:
 
3133
      audio_reset_adev (adev);
 
3134
      return 0;
 
3135
      break;
 
3136
 
 
3137
    case SNDCTL_DSP_HALT_INPUT:
 
3138
      audio_reset_input (adev);
 
3139
      return 0;
 
3140
      break;
 
3141
 
 
3142
    case SNDCTL_DSP_LOW_WATER:
 
3143
      val = *arg;
 
3144
      if (adev->open_mode & OPEN_READ)
 
3145
        adev->dmap_in->low_water = val;
 
3146
      if (adev->open_mode & OPEN_WRITE)
 
3147
        adev->dmap_out->low_water = val;
 
3148
      return 0;
 
3149
      break;
 
3150
 
 
3151
    case SNDCTL_DSP_HALT_OUTPUT:
 
3152
      audio_reset_output (adev);
 
3153
      return 0;
 
3154
      break;
 
3155
 
 
3156
    case SNDCTL_DSP_GETFMTS:
 
3157
      switch (adev->open_mode & (OPEN_READ | OPEN_WRITE))
 
3158
        {
 
3159
        case OPEN_WRITE:
 
3160
          return *arg = (adev->oformat_mask);
 
3161
          break;
 
3162
 
 
3163
        case OPEN_READ:
 
3164
          return *arg = (adev->oformat_mask);
 
3165
          break;
 
3166
 
 
3167
        default:
 
3168
          return *arg = (adev->xformat_mask);
 
3169
          break;
 
3170
        }
 
3171
      break;
 
3172
 
 
3173
    case SNDCTL_DSP_SETFMT:
 
3174
      val = *arg;
 
3175
      switch (adev->open_mode & (OPEN_READ | OPEN_WRITE))
 
3176
        {
 
3177
        case OPEN_WRITE:
 
3178
          return *arg = (oss_audio_set_format (dev, val,
 
3179
                                               audio_engines
 
3180
                                               [dev]->oformat_mask));
 
3181
          break;
 
3182
 
 
3183
        case OPEN_READ:
 
3184
          return *arg = (oss_audio_set_format (dev, val,
 
3185
                                               audio_engines
 
3186
                                               [dev]->iformat_mask));
 
3187
          break;
 
3188
 
 
3189
        default:
 
3190
          return *arg = (oss_audio_set_format (dev, val,
 
3191
                                               audio_engines
 
3192
                                               [dev]->oformat_mask &
 
3193
                                               audio_engines
 
3194
                                               [dev]->iformat_mask));
 
3195
          break;
 
3196
        }
 
3197
 
 
3198
    case SNDCTL_DSP_GETOSPACE:
 
3199
      if (!(adev->dmask & DMASK_OUT))
 
3200
        {
 
3201
          oss_audio_set_error (adev->engine_num, E_PLAY,
 
3202
                               OSSERR (1001,
 
3203
                                       "GETOSPACE called in read-only mode"),
 
3204
                               0);
 
3205
          /* Errordesc: SNDCTL_DSP_GETOSPACE is not defined in read-only access mode */
 
3206
          return OSS_ENOTSUP;
 
3207
        }
 
3208
      ret = get_ospace (adev, dmapout, arg);
 
3209
#ifdef DO_TIMINGS
 
3210
      {
 
3211
        audio_buf_info *info = (audio_buf_info *) arg;
 
3212
        oss_timing_printf ("GETOSPACE(b=%d,f=%d,fsz=%d,ft=%d)=%d", info->bytes,
 
3213
                 info->fragments, info->fragsize, info->fragstotal, ret);
 
3214
        oss_timing_printf ("Low water %d, ap flags=%x, tmpbuf=%d/%d",
 
3215
                 dmapout->low_water, adev->open_flags, dmapout->tmpbuf_ptr,
 
3216
                 dmapout->tmpbuf_len);
 
3217
      }
 
3218
#endif
 
3219
      return ret;
 
3220
      break;
 
3221
 
 
3222
    case SNDCTL_DSP_GETISPACE:
 
3223
      if (!(adev->dmask & DMASK_IN))
 
3224
        {
 
3225
          oss_audio_set_error (adev->engine_num, E_REC,
 
3226
                               OSSERR (1002,
 
3227
                                       "GETISPACE called in write-only mode"),
 
3228
                               0);
 
3229
          /*
 
3230
           * Errordesc: SNDCTL_DSP_GETISPACE has no defined meaning when the audio
 
3231
           * device is opened in write-only mode.
 
3232
           */
 
3233
          return OSS_ENOTSUP;
 
3234
        }
 
3235
 
 
3236
      return get_ispace (adev, dmapin, arg);
 
3237
      break;
 
3238
 
 
3239
    case SNDCTL_DSP_GETODELAY:
 
3240
      if (!(adev->dmask & DMASK_OUT))
 
3241
        {
 
3242
          oss_audio_set_error (adev->engine_num, E_PLAY,
 
3243
                               OSSERR (1005,
 
3244
                                       "GETODELAY called in read-only mode"),
 
3245
                               0);
 
3246
          return OSS_ENOTSUP;
 
3247
        }
 
3248
      return get_odelay (adev, dmapout, arg);
 
3249
      break;
 
3250
 
 
3251
    case SNDCTL_DSP_SETDUPLEX:
 
3252
      /*
 
3253
       * Note! SNDCTL_DSP_SETDUPLEX has not been implemented by any driver for years.
 
3254
       *       The call is still implemented in audio core but it may get removed in the
 
3255
       *       future.
 
3256
       */
 
3257
      if (adev->open_mode != OPEN_READWRITE)
 
3258
        {
 
3259
          oss_audio_set_error (adev->engine_num, E_PLAY,
 
3260
                               OSSERR (1006,
 
3261
                                       "SETDUPLEX called in non-read/write mode"),
 
3262
                               0);
 
3263
          return OSS_ENOTSUP;
 
3264
        }
 
3265
      if (adev->flags & ADEV_DUPLEX)
 
3266
        {
 
3267
          if (adev->d->adrv_ioctl == NULL)
 
3268
            return 0;
 
3269
          val = adev->d->adrv_ioctl (dev, cmd, arg);
 
3270
          if (val == OSS_EINVAL)
 
3271
            return 0;
 
3272
          else
 
3273
            return val;
 
3274
        }
 
3275
      else
 
3276
        {
 
3277
          return OSS_ENOTSUP;
 
3278
        }
 
3279
      break;
 
3280
 
 
3281
    case SNDCTL_DSP_COOKEDMODE:
 
3282
      val = *arg;
 
3283
 
 
3284
      if (adev->flags & ADEV_NONINTERLEAVED)
 
3285
         val=1;
 
3286
 
 
3287
      adev->cooked_enable = !!val;
 
3288
      if (adev->d->adrv_ioctl != NULL)
 
3289
        adev->d->adrv_ioctl (dev, cmd, arg);
 
3290
#ifdef DO_TIMINGS
 
3291
      if (adev->cooked_enable)
 
3292
        oss_do_timing ("Setting cooked mode ON");
 
3293
      else
 
3294
        oss_do_timing ("Setting cooked mode OFF");
 
3295
#endif
 
3296
      return 0;
 
3297
      break;
 
3298
 
 
3299
    case SNDCTL_DSP_GETCAPS:
 
3300
      {
 
3301
        int info;
 
3302
        info = audio_engines[dev]->caps;
 
3303
        info |= 2;              /* Revision level of this ioctl() */
 
3304
 
 
3305
#if 0
 
3306
        if (!(adev->flags & ADEV_VIRTUAL) && !adev->d->adrv_local_qlen)
 
3307
#endif
 
3308
          info |= PCM_CAP_REALTIME;
 
3309
 
 
3310
 
 
3311
        if (!(adev->flags & ADEV_NOINPUT))
 
3312
          info |= PCM_CAP_INPUT;
 
3313
 
 
3314
        if (!(adev->flags & ADEV_NOOUTPUT))
 
3315
          info |= PCM_CAP_OUTPUT;
 
3316
 
 
3317
        if ((adev->flags & ADEV_VIRTUAL))
 
3318
          info |= PCM_CAP_VIRTUAL;
 
3319
 
 
3320
        if (!(adev->flags & ADEV_NOINPUT) && !(adev->flags & ADEV_NOOUTPUT))
 
3321
          if (adev->flags & ADEV_DUPLEX && adev->open_mode == OPEN_READWRITE)
 
3322
            info |= PCM_CAP_DUPLEX;
 
3323
 
 
3324
        if (dev > 0)
 
3325
          if (adev->flags & ADEV_SPECIAL)
 
3326
            info |= PCM_CAP_SPECIAL;
 
3327
 
 
3328
        if (dev < num_audio_engines - 1)
 
3329
          {
 
3330
            if (audio_engines[dev + 1]->flags & ADEV_SHADOW)
 
3331
              info |= PCM_CAP_MULTI;
 
3332
          }
 
3333
 
 
3334
        if (adev->d->adrv_local_qlen)   /* Device has hidden buffers */
 
3335
          info |= PCM_CAP_BATCH;
 
3336
 
 
3337
        if (adev->d->adrv_trigger)      /* Supports SETTRIGGER */
 
3338
          info |= PCM_CAP_TRIGGER;
 
3339
 
 
3340
#ifdef ALLOW_BUFFER_MAPPING
 
3341
        info |= PCM_CAP_MMAP;
 
3342
#endif
 
3343
        if (!(adev->flags & ADEV_NOINPUT))
 
3344
          info |= PCM_CAP_INPUT;
 
3345
 
 
3346
        if (!(adev->flags & ADEV_NOOUTPUT))
 
3347
          info |= PCM_CAP_OUTPUT;
 
3348
 
 
3349
        if (adev->d->adrv_bind != NULL)
 
3350
          info |= PCM_CAP_BIND;
 
3351
        /*
 
3352
         * TODO: ADEV_DEFAULT is not the right way to find out 
 
3353
         * PCM_CAP_DEFAULT devices. A new ADEV_ flag should be defined
 
3354
         * for this purpose.
 
3355
         */
 
3356
        if (adev->flags & ADEV_DEFAULT)
 
3357
          info |= PCM_CAP_DEFAULT;
 
3358
 
 
3359
        return *arg = (info);
 
3360
      }
 
3361
      break;
 
3362
 
 
3363
    case SNDCTL_DSP_NONBLOCK:
 
3364
      adev->forced_nonblock = 1;
 
3365
      return 0;
 
3366
      break;
 
3367
 
 
3368
    case SNDCTL_DSP_GETCHANNELMASK:
 
3369
    case SNDCTL_DSP_BIND_CHANNEL:
 
3370
      if (adev->d->adrv_bind == NULL)
 
3371
        return OSS_EINVAL;
 
3372
      return adev->d->adrv_bind (adev->engine_num, cmd, arg);
 
3373
      break;
 
3374
 
 
3375
    case SNDCTL_DSP_SETTRIGGER:
 
3376
      {
 
3377
        int val;
 
3378
 
 
3379
        if (!adev->d->adrv_trigger)
 
3380
          {
 
3381
            cmn_err (CE_NOTE, "Device %d doesn't have trigger capability\n",
 
3382
                     adev->engine_num);
 
3383
            return OSS_EIO;
 
3384
          }
 
3385
 
 
3386
        val = *arg;
 
3387
        val &= PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
 
3388
        val &= adev->open_mode;
 
3389
 
 
3390
        if ((val & adev->open_mode) != (adev->enable_bits & adev->open_mode))
 
3391
          {
 
3392
            if ((val & PCM_ENABLE_OUTPUT)
 
3393
                && !(adev->enable_bits & PCM_ENABLE_OUTPUT))
 
3394
              {
 
3395
                dmap_p dmap = adev->dmap_out;
 
3396
                oss_native_word flags;
 
3397
                if (adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)
 
3398
                  dmap->dma_mode = PCM_ENABLE_OUTPUT;
 
3399
                if ((err = prepare_output (adev, adev->dmap_out)) < 0)
 
3400
                  return err;
 
3401
                launch_output (adev, adev->dmap_out);
 
3402
                MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
3403
                adev->enable_bits &= PCM_ENABLE_OUTPUT;
 
3404
                adev->enable_bits |= val & PCM_ENABLE_OUTPUT;
 
3405
                MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
3406
              }
 
3407
 
 
3408
            if ((val & PCM_ENABLE_INPUT)
 
3409
                && !(adev->enable_bits & PCM_ENABLE_INPUT))
 
3410
              {
 
3411
                dmap_p dmap = adev->dmap_in;
 
3412
                oss_native_word flags;
 
3413
                MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
3414
                dmap->dma_mode = PCM_ENABLE_INPUT;
 
3415
                MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
3416
                if ((err = prepare_input (adev, adev->dmap_in)) < 0)
 
3417
                  return err;
 
3418
                MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
3419
                launch_input (adev, adev->dmap_in);
 
3420
                adev->enable_bits &= PCM_ENABLE_INPUT;
 
3421
                adev->enable_bits |= val & PCM_ENABLE_INPUT;
 
3422
                MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
3423
              }
 
3424
 
 
3425
            adev->enable_bits = val;
 
3426
            if (adev->enable_bits == 0 || adev->go)     /* Device is enabled */
 
3427
              {
 
3428
                adev->d->adrv_trigger (adev->engine_num, adev->enable_bits);
 
3429
              }
 
3430
          }
 
3431
        *arg = val;
 
3432
        return 0;
 
3433
      }
 
3434
      break;
 
3435
 
 
3436
    case SNDCTL_DSP_GETTRIGGER:
 
3437
      if (!adev->d->adrv_trigger)
 
3438
        {
 
3439
          cmn_err (CE_NOTE, "Device %d doesn't have trigger capability\n",
 
3440
                   adev->engine_num);
 
3441
          return OSS_EIO;
 
3442
        }
 
3443
      return *arg = (adev->enable_bits & adev->open_mode);
 
3444
      break;
 
3445
 
 
3446
    case SNDCTL_DSP_SETSYNCRO:
 
3447
      adev->go = 0;
 
3448
      break;
 
3449
 
 
3450
    case SNDCTL_DSP_SYNCGROUP:
 
3451
      return handle_syncgroup (adev, (oss_syncgroup *) arg);
 
3452
      break;
 
3453
 
 
3454
    case SNDCTL_DSP_SYNCSTART:
 
3455
      val = *arg;
 
3456
 
 
3457
      MUTEX_ENTER_IRQDISABLE (audio_global_mutex, flags);
 
3458
      ret = handle_syncstart (adev->engine_num, val);
 
3459
      MUTEX_EXIT_IRQRESTORE (audio_global_mutex, flags);
 
3460
 
 
3461
      return ret;
 
3462
      break;
 
3463
 
 
3464
    case SNDCTL_DSP_GETERROR:
 
3465
      {
 
3466
        audio_errinfo *info = (audio_errinfo *) arg;
 
3467
 
 
3468
        memset ((void *) info, 0, sizeof (*info));
 
3469
 
 
3470
        //if (audio_engines[dev]->open_mode & OPEN_READ)
 
3471
        {
 
3472
          dmap_t *dmap = audio_engines[dev]->dmap_in;
 
3473
 
 
3474
          info->rec_overruns = dmap->rec_overruns;
 
3475
          dmap->rec_overruns = 0;
 
3476
          info->rec_ptradjust = 0;
 
3477
          info->rec_errorcount = dmap->num_errors;
 
3478
          info->rec_lasterror = dmap->errors[0];
 
3479
          info->rec_errorparm = dmap->error_parms[0];
 
3480
        }
 
3481
 
 
3482
        //if (audio_engines[dev]->open_mode & OPEN_WRITE)
 
3483
        {
 
3484
          dmap_t *dmap = audio_engines[dev]->dmap_out;
 
3485
 
 
3486
          info->play_underruns = dmap->play_underruns;
 
3487
          dmap->play_underruns = 0;
 
3488
          info->play_ptradjust = 0;
 
3489
          info->play_errorcount = dmap->num_errors;
 
3490
          info->play_lasterror = dmap->errors[0];
 
3491
          info->play_errorparm = dmap->error_parms[0];
 
3492
        }
 
3493
 
 
3494
        return 0;
 
3495
      }
 
3496
      break;
 
3497
 
 
3498
    case SNDCTL_DSP_GETPLAYVOL:
 
3499
    case SNDCTL_DSP_SETPLAYVOL:
 
3500
      {
 
3501
        int err, mixdev;
 
3502
 
 
3503
        mixdev = adev->mixer_dev;
 
3504
        if (cmd == SNDCTL_DSP_SETPLAYVOL && mixdev >= 0
 
3505
            && mixdev < num_mixers)
 
3506
          mixer_devs[mixdev]->modify_counter++;
 
3507
 
 
3508
        if (adev->d->adrv_ioctl == NULL
 
3509
            || (err = adev->d->adrv_ioctl (dev, cmd, arg)) == OSS_EINVAL)
 
3510
          {
 
3511
            /* Emulate these calls using mixer API */
 
3512
 
 
3513
            if (mixdev < 0 || mixdev >= num_mixers)
 
3514
              return OSS_EINVAL;
 
3515
 
 
3516
            if (cmd == SNDCTL_DSP_GETPLAYVOL)
 
3517
              cmd = SOUND_MIXER_READ_PCM;
 
3518
            else
 
3519
              cmd = SOUND_MIXER_WRITE_PCM;
 
3520
            return mixer_devs[mixdev]->d->ioctl (mixdev, dev, cmd, arg);
 
3521
          }
 
3522
        return err;
 
3523
      }
 
3524
      break;
 
3525
 
 
3526
    case SNDCTL_DSP_GETRECVOL:
 
3527
    case SNDCTL_DSP_SETRECVOL:
 
3528
      {
 
3529
        int err, mixdev;
 
3530
 
 
3531
        mixdev = adev->mixer_dev;
 
3532
        if (cmd == SNDCTL_DSP_SETRECVOL && mixdev >= 0 && mixdev < num_mixers)
 
3533
          mixer_devs[mixdev]->modify_counter++;
 
3534
 
 
3535
        if (adev->d->adrv_ioctl == NULL
 
3536
            || (err = adev->d->adrv_ioctl (dev, cmd, arg)) == OSS_EINVAL)
 
3537
          {
 
3538
            /* Emulate these calls using mixer API */
 
3539
 
 
3540
            if (mixdev < 0 || mixdev >= num_mixers)
 
3541
              return OSS_EINVAL;
 
3542
 
 
3543
            /* Try with RECGAIN */
 
3544
            if (cmd == SNDCTL_DSP_GETRECVOL)
 
3545
              cmd = SOUND_MIXER_READ_RECGAIN;
 
3546
            else
 
3547
              cmd = SOUND_MIXER_WRITE_RECGAIN;
 
3548
            err = mixer_devs[mixdev]->d->ioctl (mixdev, dev, cmd, arg);
 
3549
 
 
3550
            /* Try with RECLEV */
 
3551
            if (cmd == SNDCTL_DSP_GETRECVOL)
 
3552
              cmd = SOUND_MIXER_READ_RECLEV;
 
3553
            else
 
3554
              cmd = SOUND_MIXER_WRITE_RECLEV;
 
3555
            err = mixer_devs[mixdev]->d->ioctl (mixdev, dev, cmd, arg);
 
3556
 
 
3557
            if (err >= 0)       /* Was OK */
 
3558
              return err;
 
3559
 
 
3560
            /* Try with IGAIN */
 
3561
            if (cmd == SNDCTL_DSP_GETRECVOL)
 
3562
              cmd = SOUND_MIXER_READ_IGAIN;
 
3563
            else
 
3564
              cmd = SOUND_MIXER_WRITE_IGAIN;
 
3565
            return mixer_devs[mixdev]->d->ioctl (mixdev, dev, cmd, arg);
 
3566
          }
 
3567
        return err;
 
3568
      }
 
3569
      break;
 
3570
 
 
3571
    case SNDCTL_DSP_GETOPTR:
 
3572
      if (!(adev->dmask & DMASK_OUT))
 
3573
        {
 
3574
          oss_audio_set_error (adev->engine_num, E_PLAY,
 
3575
                               OSSERR (1007,
 
3576
                                       "GETOPTR called in read-only mode"),
 
3577
                               0);
 
3578
          return OSS_ENOTSUP;
 
3579
        }
 
3580
      return get_optr (adev, dmapout, arg);
 
3581
      break;
 
3582
 
 
3583
    case SNDCTL_DSP_GETIPTR:
 
3584
      if (!(adev->dmask & DMASK_IN))
 
3585
        {
 
3586
          oss_audio_set_error (adev->engine_num, E_REC,
 
3587
                               OSSERR (1008,
 
3588
                                       "GETIPTR called in write-only mode"),
 
3589
                               0);
 
3590
          return OSS_ENOTSUP;
 
3591
        }
 
3592
      return get_iptr (adev, dmapin, arg);
 
3593
      break;
 
3594
 
 
3595
#ifndef OSS_NO_LONG_LONG
 
3596
    case SNDCTL_DSP_CURRENT_OPTR:
 
3597
      if (!(adev->dmask & DMASK_OUT))
 
3598
        return OSS_ENOTSUP;
 
3599
      return get_long_optr (adev, dmapout, arg);
 
3600
      break;
 
3601
 
 
3602
    case SNDCTL_DSP_CURRENT_IPTR:
 
3603
      if (!(adev->dmask & DMASK_IN))
 
3604
        return OSS_ENOTSUP;
 
3605
      return get_long_iptr (adev, dmapin, arg);
 
3606
      break;
 
3607
#endif
 
3608
 
 
3609
    case SNDCTL_DSP_POLICY:
 
3610
      val = *arg;
 
3611
      if (val < 0 || val > 10)
 
3612
        return OSS_EIO;
 
3613
      adev->policy = val;
 
3614
      return 0;
 
3615
      break;
 
3616
 
 
3617
    case SNDCTL_DSP_SETFRAGMENT:
 
3618
    case SNDCTL_DSP_SUBDIVIDE:
 
3619
      if (cmd == SNDCTL_DSP_SUBDIVIDE)
 
3620
        {
 
3621
          oss_audio_set_error (adev->engine_num, E_PLAY,
 
3622
                               OSSERR (1010,
 
3623
                                       "SNDCTL_DSP_SUBDIVIDE is obsolete"),
 
3624
                               0);
 
3625
          /*
 
3626
           * Errordesc:
 
3627
           * SNDCTL_DSP_SUBDIVIDE is obsolete. It's still emulated by OSS but
 
3628
           * the result is not precise. You need to use SNDCTL_DSP_SETFRAGMENT
 
3629
           * instead.
 
3630
           */
 
3631
          *arg = 0x00040008;    /* Default to 4 fragments of 256 bytes */
 
3632
        }
 
3633
 
 
3634
      val = *arg;
 
3635
      if (adev->dmask & DMASK_OUT)
 
3636
        {
 
3637
          if (dmapout->flags & DMAP_FRAGFIXED)
 
3638
            setfragment_error (dev);
 
3639
          dmapout->fragsize_rq = val;
 
3640
        }
 
3641
      if (adev->dmask & DMASK_IN)
 
3642
        {
 
3643
          if (dmapin->flags & DMAP_FRAGFIXED)
 
3644
            setfragment_error (dev);
 
3645
          dmapin->fragsize_rq = val;
 
3646
        }
 
3647
      return 0;
 
3648
 
 
3649
#ifdef __FreeBSD__
 
3650
    case FREEBSD_GETBLKSIZE:
 
3651
#endif
 
3652
    case SNDCTL_DSP_GETBLKSIZE:
 
3653
      return *arg = getblksize (adev);
 
3654
 
 
3655
    case SNDCTL_DSP_SPEED:
 
3656
      val = *arg;
 
3657
      if (val<0)
 
3658
         return OSS_EINVAL;
 
3659
      return *arg = (oss_audio_set_rate (dev, val));
 
3660
 
 
3661
    case SNDCTL_DSP_STEREO:
 
3662
      {
 
3663
        int n, v;
 
3664
 
 
3665
        n = *arg;
 
3666
        if (n > 1)
 
3667
          {
 
3668
            oss_audio_set_error (adev->engine_num, E_PLAY,
 
3669
                                 OSSERR (1009,
 
3670
                                         "SNDCTL_DSP_STEREO called with bad agrument value"),
 
3671
                                 n);
 
3672
            /*
 
3673
             * Errordesc: SNDCTL_DSP_STEREO is an obsolete ioctl call that
 
3674
             * supports only mono (0) or stereo (1). For larger number of channels
 
3675
             * you need to use SNDCTL_DSP_CHANNELS instead.
 
3676
             */
 
3677
            return OSS_EINVAL;
 
3678
          }
 
3679
 
 
3680
        if (n < 0)
 
3681
          return OSS_EINVAL;
 
3682
 
 
3683
        v = oss_audio_set_channels (dev, n + 1);
 
3684
        return *arg = (v - 1);
 
3685
      }
 
3686
 
 
3687
    case SNDCTL_DSP_CHANNELS:
 
3688
      {
 
3689
        int v;
 
3690
        val = *arg;
 
3691
#ifdef DO_TIMINGS
 
3692
        {
 
3693
          char tmp[128];
 
3694
 
 
3695
          sprintf (tmp, "Set channels %d", (int) val);
 
3696
          oss_do_timing2 (DFLAG_PROFILE, tmp);
 
3697
        }
 
3698
#endif
 
3699
        if (val<0)
 
3700
        {
 
3701
                return OSS_EINVAL;
 
3702
        }
 
3703
        v = oss_audio_set_channels (dev, val);
 
3704
        return *arg = v;
 
3705
      }
 
3706
 
 
3707
    case SNDCTL_DSP_PROFILE:    /* Obsolete */
 
3708
      return 0;
 
3709
      break;
 
3710
 
 
3711
    case SNDCTL_DSP_SILENCE:
 
3712
      memset (dmapout->dmabuf, dmapout->neutral_byte, dmapout->buffsize);
 
3713
      return 0;
 
3714
      break;
 
3715
 
 
3716
    case SNDCTL_DSP_SKIP:
 
3717
      return 0;
 
3718
      break;
 
3719
 
 
3720
    case SNDCTL_DSP_GET_RECSRC_NAMES:
 
3721
      if (adev->d->adrv_ioctl == NULL || (err = adev->d->adrv_ioctl (dev, cmd, arg)) == OSS_EINVAL)     /* Not handled */
 
3722
        {
 
3723
          oss_mixer_enuminfo *ei = (oss_mixer_enuminfo *) arg;
 
3724
 
 
3725
          memset (ei, 0, sizeof (*ei)); /* Wipe out everything */
 
3726
 
 
3727
          if (get_legacy_recsrc_names (dev, ei))
 
3728
            return 0;
 
3729
          ei->nvalues = 1;
 
3730
          strcpy (ei->strings, "default");
 
3731
          return 0;
 
3732
        }
 
3733
      return err;
 
3734
      break;
 
3735
 
 
3736
    case SNDCTL_DSP_GET_RECSRC:
 
3737
      if (adev->d->adrv_ioctl == NULL || (err = adev->d->adrv_ioctl (dev, cmd, arg)) == OSS_EINVAL)     /* Not handled */
 
3738
        {
 
3739
          return *arg = (get_legacy_recsrc (dev));
 
3740
        }
 
3741
      return err;
 
3742
      break;
 
3743
 
 
3744
    case SNDCTL_DSP_SET_RECSRC:
 
3745
      if (adev->d->adrv_ioctl == NULL || (err = adev->d->adrv_ioctl (dev, cmd, arg)) == OSS_EINVAL)     /* Not handled */
 
3746
        {
 
3747
          val = *arg;
 
3748
          set_legacy_recsrc (dev, val);
 
3749
          return *arg = (get_legacy_recsrc (dev));
 
3750
        }
 
3751
      return err;
 
3752
      break;
 
3753
 
 
3754
    case SNDCTL_DSP_GET_PLAYTGT_NAMES:
 
3755
      if (adev->d->adrv_ioctl == NULL || (err = adev->d->adrv_ioctl (dev, cmd, arg)) == OSS_EINVAL)     /* Not handled */
 
3756
        {
 
3757
          oss_mixer_enuminfo *ei = (oss_mixer_enuminfo *) arg;
 
3758
          memset (ei, 0, sizeof (*ei));
 
3759
          ei->nvalues = 1;
 
3760
          strcpy (ei->strings, "default");
 
3761
          return 0;
 
3762
        }
 
3763
      return err;
 
3764
      break;
 
3765
 
 
3766
    case SNDCTL_DSP_GET_PLAYTGT:
 
3767
      if (adev->d->adrv_ioctl == NULL || (err = adev->d->adrv_ioctl (dev, cmd, arg)) == OSS_EINVAL)     /* Not handled */
 
3768
        {
 
3769
          return *arg = (0);
 
3770
        }
 
3771
      return err;
 
3772
      break;
 
3773
 
 
3774
    case SNDCTL_DSP_SET_PLAYTGT:
 
3775
      if (adev->d->adrv_ioctl == NULL || (err = adev->d->adrv_ioctl (dev, cmd, arg)) == OSS_EINVAL)     /* Not handled */
 
3776
        {
 
3777
          return *arg = (0);
 
3778
        }
 
3779
      return err;
 
3780
      break;
 
3781
 
 
3782
    case SNDCTL_SETSONG:
 
3783
      if (adev->d->adrv_ioctl != NULL
 
3784
          && adev->d->adrv_ioctl (dev, cmd, arg) >= 0)
 
3785
        return 0;
 
3786
      strncpy (adev->song_name, (char *) arg, sizeof (adev->song_name));
 
3787
      adev->song_name[sizeof (adev->song_name) - 1] = 0;
 
3788
      return 0;
 
3789
      break;
 
3790
 
 
3791
    case SNDCTL_SETLABEL:
 
3792
      if (adev->d->adrv_ioctl != NULL
 
3793
          && adev->d->adrv_ioctl (dev, cmd, arg) >= 0)
 
3794
        return 0;
 
3795
      strncpy (adev->label, (char *) arg, sizeof (adev->label));
 
3796
      adev->label[sizeof (adev->label) - 1] = 0;
 
3797
      if (*adev->cmd == 0)      /* Command name not known */
 
3798
        strcpy (adev->cmd, adev->label);
 
3799
      return 0;
 
3800
      break;
 
3801
    default:
 
3802
      if (adev->d->adrv_ioctl == NULL)
 
3803
        return OSS_EINVAL;
 
3804
      return adev->d->adrv_ioctl (dev, cmd, arg);
 
3805
    }
 
3806
  return OSS_EINVAL;
 
3807
}
 
3808
 
 
3809
 
 
3810
static int
 
3811
prepare_output (adev_p adev, dmap_p dmap)
 
3812
{
 
3813
  int ret, data_rate = 0;
 
3814
  audio_format_info_p fmt_info;
 
3815
 
 
3816
  if (dmap->flags & DMAP_PREPARED)
 
3817
    return 0;
 
3818
 
 
3819
  data_rate = 8;
 
3820
 
 
3821
  dmap->flags &= ~DMAP_COOKED;
 
3822
  adev->user_parms.convert = 0;
 
3823
  adev->hw_parms.convert = 0;
 
3824
  dmap->convert_func = NULL;
 
3825
  dmap->convert_mode = 0;
 
3826
  dmap->expand_factor = UNIT_EXPAND;
 
3827
 
 
3828
  if (adev->user_parms.rate != adev->hw_parms.rate)
 
3829
    dmap->flags |= DMAP_COOKED;
 
3830
  if (adev->user_parms.fmt != adev->hw_parms.fmt)
 
3831
    dmap->flags |= DMAP_COOKED;
 
3832
  if (adev->user_parms.channels != adev->hw_parms.channels)
 
3833
    dmap->flags |= DMAP_COOKED;
 
3834
  if ((adev->flags & ADEV_NONINTERLEAVED) && adev->hw_parms.channels > 1)
 
3835
    dmap->flags |= DMAP_COOKED;
 
3836
 
 
3837
#if 1
 
3838
  if (always_cooked && !(dmap->mapping_flags & DMA_MAP_MAPPED))
 
3839
    dmap->flags |= DMAP_COOKED;
 
3840
#endif
 
3841
 
 
3842
  if ((dmap->mapping_flags & DMA_MAP_MAPPED) && (dmap->flags & DMAP_COOKED))
 
3843
    {
 
3844
      cmn_err (CE_WARN, "Internal error in mmap() support\n");
 
3845
      dmap->flags &= ~DMAP_COOKED;
 
3846
    }
 
3847
 
 
3848
  if (dmap->flags & DMAP_COOKED)
 
3849
    {
 
3850
#ifdef DO_TIMINGS
 
3851
      oss_do_timing ("Cooked mode - Setting up conversions");
 
3852
#endif
 
3853
      if ((ret =
 
3854
           setup_format_conversions (adev, dmap, &adev->user_parms,
 
3855
                                     &adev->hw_parms,
 
3856
                                     &adev->user_parms,
 
3857
                                     &adev->hw_parms,
 
3858
                                     adev->oformat_mask)) < 0)
 
3859
        {
 
3860
          return ret;
 
3861
        }
 
3862
    }
 
3863
  else
 
3864
    {
 
3865
      DDB (cmn_err (CE_CONT, "No format conversions needed\n"));
 
3866
#ifdef DO_TIMINGS
 
3867
      oss_do_timing ("No format conversions needed");
 
3868
#endif
 
3869
    }
 
3870
 
 
3871
/*
 
3872
 * Compute device data rate and frame size
 
3873
 */
 
3874
  if ((fmt_info = oss_find_format (adev->hw_parms.fmt)) != NULL)
 
3875
    data_rate = fmt_info->bits;
 
3876
 
 
3877
  data_rate /= 8;
 
3878
  if (data_rate < 1)
 
3879
    data_rate = 1;
 
3880
  data_rate *= adev->hw_parms.channels;
 
3881
  dmap->frame_size = data_rate;
 
3882
  data_rate *= adev->hw_parms.rate;
 
3883
  if (data_rate < 1)
 
3884
    data_rate = 8000;
 
3885
  dmap->data_rate = data_rate;
 
3886
 
 
3887
/*
 
3888
 * Compute application/user frame_size
 
3889
 */
 
3890
  data_rate = 8;
 
3891
  if ((fmt_info = oss_find_format (adev->user_parms.fmt)) != NULL)
 
3892
    data_rate = fmt_info->bits;
 
3893
 
 
3894
  data_rate /= 8;
 
3895
  if (data_rate < 1)
 
3896
    data_rate = 1;
 
3897
  data_rate *= adev->user_parms.channels;
 
3898
  dmap->user_frame_size = data_rate;
 
3899
 
 
3900
  setup_fragments (adev, dmap, OPEN_WRITE);
 
3901
  if (dmap->expand_factor == 0)
 
3902
    {
 
3903
      dmap->expand_factor = UNIT_EXPAND;
 
3904
      cmn_err (CE_WARN, "Bad expand factor for device %d\n",
 
3905
               adev->engine_num);
 
3906
    }
 
3907
  if (dmap->low_water == -1)
 
3908
    {
 
3909
      dmap->low_water =
 
3910
        (dmap->low_water_rq * UNIT_EXPAND) / dmap->expand_factor;
 
3911
    }
 
3912
 
 
3913
#ifdef DO_TIMINGS
 
3914
     oss_timing_printf ("Prepare output dev=%d, fragsize=%d, nfrags=%d, bytes_in_use=%d/%d",
 
3915
             adev->engine_num, dmap->fragment_size, dmap->nfrags,
 
3916
             dmap->bytes_in_use, dmap->buffsize);
 
3917
#endif
 
3918
 
 
3919
  if ((ret =
 
3920
       adev->d->adrv_prepare_for_output (adev->engine_num,
 
3921
                                         dmap->fragment_size,
 
3922
                                         dmap->nfrags)) < 0)
 
3923
    {
 
3924
      return ret;
 
3925
    }
 
3926
 
 
3927
  dmap->flags |= DMAP_PREPARED;
 
3928
#ifdef CONFIG_OSSD
 
3929
  ossd_event (adev->engine_num, OSSD_EV_PREPARE_OUTPUT);
 
3930
#endif
 
3931
 
 
3932
  return 0;
 
3933
}
 
3934
 
 
3935
static int
 
3936
prepare_input (adev_p adev, dmap_p dmap)
 
3937
{
 
3938
  int ret, data_rate = 0;
 
3939
  audio_format_info_p fmt_info;
 
3940
 
 
3941
  if (dmap->flags & DMAP_PREPARED)
 
3942
    return 0;
 
3943
 
 
3944
  data_rate = 0;
 
3945
 
 
3946
  dmap->flags &= ~DMAP_COOKED;
 
3947
  adev->user_parms.convert = 0;
 
3948
  adev->hw_parms.convert = 0;
 
3949
  dmap->convert_func = NULL;
 
3950
  dmap->convert_mode = 0;
 
3951
  dmap->expand_factor = UNIT_EXPAND;
 
3952
 
 
3953
  if (adev->user_parms.rate != adev->hw_parms.rate)
 
3954
    dmap->flags |= DMAP_COOKED;
 
3955
  if (adev->user_parms.fmt != adev->hw_parms.fmt)
 
3956
    dmap->flags |= DMAP_COOKED;
 
3957
  if (adev->user_parms.channels != adev->hw_parms.channels)
 
3958
    dmap->flags |= DMAP_COOKED;
 
3959
  if ((adev->flags & ADEV_NONINTERLEAVED) && adev->hw_parms.channels > 1)
 
3960
    dmap->flags |= DMAP_COOKED;
 
3961
 
 
3962
#if 1
 
3963
  if (always_cooked && !(dmap->mapping_flags & DMA_MAP_MAPPED))
 
3964
    dmap->flags |= DMAP_COOKED;
 
3965
#endif
 
3966
 
 
3967
  if ((dmap->mapping_flags & DMA_MAP_MAPPED) && (dmap->flags & DMAP_COOKED))
 
3968
    {
 
3969
      cmn_err (CE_WARN, "Internal error in mmap() support\n");
 
3970
      dmap->flags &= ~DMAP_COOKED;
 
3971
    }
 
3972
 
 
3973
  if (dmap->flags & DMAP_COOKED)
 
3974
    {
 
3975
      if ((ret =
 
3976
           setup_format_conversions (adev, dmap, &adev->hw_parms,
 
3977
                                     &adev->user_parms,
 
3978
                                     &adev->user_parms,
 
3979
                                     &adev->hw_parms,
 
3980
                                     adev->iformat_mask)) < 0)
 
3981
        {
 
3982
          DDB (cmn_err
 
3983
               (CE_CONT, "setup_format_conversions failed, err=%d\n", ret));
 
3984
          return ret;
 
3985
        }
 
3986
    }
 
3987
  else
 
3988
    dmap->expand_factor = UNIT_EXPAND;
 
3989
 
 
3990
/*
 
3991
 * Compute device data rate and frame size
 
3992
 */
 
3993
  if ((fmt_info = oss_find_format (adev->hw_parms.fmt)) != NULL)
 
3994
    data_rate = fmt_info->bits;
 
3995
 
 
3996
  data_rate /= 8;
 
3997
  if (data_rate < 1)
 
3998
    data_rate = 1;
 
3999
  data_rate *= adev->hw_parms.channels;
 
4000
  dmap->frame_size = data_rate;
 
4001
  data_rate *= adev->hw_parms.rate;
 
4002
  if (data_rate < 1)
 
4003
    data_rate = 8000;
 
4004
  dmap->data_rate = data_rate;
 
4005
 
 
4006
/*
 
4007
 * Compute user/application frame size
 
4008
 */
 
4009
  data_rate = 8;
 
4010
  if ((fmt_info = oss_find_format (adev->user_parms.fmt)) != NULL)
 
4011
    data_rate = fmt_info->bits;
 
4012
 
 
4013
  data_rate /= 8;
 
4014
  if (data_rate < 1)
 
4015
    data_rate = 1;
 
4016
  data_rate *= adev->user_parms.channels;
 
4017
  dmap->user_frame_size = data_rate;
 
4018
 
 
4019
  setup_fragments (adev, dmap, OPEN_READ);
 
4020
 
 
4021
#if 1
 
4022
  /* Compute 1/expand_factor */
 
4023
 
 
4024
  if (dmap->expand_factor == 0)
 
4025
    {
 
4026
      cmn_err (CE_NOTE, "Internal error (expand_factor==0)\n");
 
4027
      dmap->expand_factor = UNIT_EXPAND;
 
4028
    }
 
4029
 
 
4030
  {
 
4031
    int expand = dmap->expand_factor;
 
4032
    int expand2 = expand * 100 / UNIT_EXPAND;
 
4033
    DDB (cmn_err (CE_CONT, "Expand factor was = %d (%d.%02d)\n", expand,
 
4034
                  expand2 / 100, expand2 % 100));
 
4035
  }
 
4036
 
 
4037
  dmap->expand_factor = (UNIT_EXPAND * UNIT_EXPAND) / dmap->expand_factor;
 
4038
 
 
4039
  {
 
4040
    int expand = dmap->expand_factor;
 
4041
    int expand2 = expand * 100 / UNIT_EXPAND;
 
4042
    DDB (cmn_err
 
4043
         (CE_CONT, "Expand factor inverted to = %d (%d.%02d)\n", expand,
 
4044
          expand2 / 100, expand2 % 100));
 
4045
  }
 
4046
#endif
 
4047
 
 
4048
  if (dmap->low_water == -1)
 
4049
    {
 
4050
      dmap->low_water =
 
4051
        (dmap->low_water_rq * UNIT_EXPAND) / dmap->expand_factor;
 
4052
    }
 
4053
 
 
4054
#ifdef DO_TIMINGS
 
4055
     oss_timing_printf ("Prepare input dev=%d, fragsize=%d, nfrags=%d, bytes_in_use=%d",
 
4056
             adev->engine_num, dmap->fragment_size, dmap->nfrags,
 
4057
             dmap->bytes_in_use);
 
4058
#endif
 
4059
 
 
4060
  if ((ret =
 
4061
       adev->d->adrv_prepare_for_input (adev->engine_num, dmap->fragment_size,
 
4062
                                        dmap->nfrags)) < 0)
 
4063
    {
 
4064
      DDB (cmn_err
 
4065
           (CE_CONT, "/dev/dsp%d: prepare_for_input failed, err=%d\n",
 
4066
            adev->engine_num, ret));
 
4067
      return ret;
 
4068
    }
 
4069
 
 
4070
  dmap->flags |= DMAP_PREPARED;
 
4071
#ifdef CONFIG_OSSD
 
4072
  ossd_event (adev->engine_num, OSSD_EV_PREPARE_INPUT);
 
4073
#endif
 
4074
 
 
4075
  return 0;
 
4076
}
 
4077
 
 
4078
static int
 
4079
launch_input (adev_p adev, dmap_p dmap)
 
4080
{
 
4081
#ifdef DO_TIMINGS
 
4082
  oss_do_timing ("Launch input called");
 
4083
#endif
 
4084
  if (dmap->flags & DMAP_STARTED)
 
4085
    return 0;
 
4086
 
 
4087
  if (!(dmap->flags & DMAP_PREPARED))
 
4088
    {
 
4089
      cmn_err (CE_WARN, "launch_input while not prepared.\n");
 
4090
      return OSS_EIO;
 
4091
    }
 
4092
 
 
4093
#ifdef DO_TIMINGS
 
4094
  oss_do_timing ("Launch_input calling d->start_input");
 
4095
#endif
 
4096
 
 
4097
  if (adev->d->adrv_start_input != NULL)
 
4098
    {
 
4099
      if (adev->flags & ADEV_AUTOMODE)
 
4100
        adev->d->adrv_start_input (adev->engine_num, dmap->dmabuf_phys,
 
4101
                                   dmap->bytes_in_use, dmap->fragment_size,
 
4102
                                   0);
 
4103
      else
 
4104
        adev->d->adrv_start_input (adev->engine_num, dmap->dmabuf_phys,
 
4105
                                   dmap->fragment_size, dmap->fragment_size,
 
4106
                                   0);
 
4107
    }
 
4108
 
 
4109
#ifdef DO_TIMINGS
 
4110
  oss_do_timing ("Launch_input calling trigger");
 
4111
#endif
 
4112
  dmap->flags |= DMAP_STARTED;
 
4113
  if (adev->d->adrv_trigger
 
4114
      && ((adev->enable_bits * adev->go) & PCM_ENABLE_INPUT))
 
4115
    {
 
4116
      adev->d->adrv_trigger (adev->engine_num, adev->enable_bits * adev->go);
 
4117
    }
 
4118
 
 
4119
  return 0;
 
4120
}
 
4121
 
 
4122
static int
 
4123
find_raw_input_space (adev_p adev, dmap_p dmap, int *dmapos)
 
4124
{
 
4125
  int count;
 
4126
  int tmout, n = 0;
 
4127
  oss_uint64_t offs, doffs;
 
4128
  int lim = 1;
 
4129
  unsigned int status;
 
4130
  oss_native_word flags;
 
4131
 
 
4132
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
4133
  if (adev->nonblock)
 
4134
    get_input_pointer (adev, dmap, 1);
 
4135
  count = (int) (dmap->byte_counter - dmap->user_counter);
 
4136
  *dmapos=0;
 
4137
 
 
4138
  if (dmap->flags & DMAP_COOKED)
 
4139
    {
 
4140
      lim = dmap->fragment_size;
 
4141
    }
 
4142
 
 
4143
  while (count < lim)
 
4144
    {
 
4145
      if (adev->nonblock)
 
4146
        {
 
4147
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4148
#ifdef DO_TIMINGS
 
4149
          oss_do_timing ("*** EAGAIN ***");
 
4150
#endif
 
4151
          return OSS_EAGAIN;
 
4152
        }
 
4153
 
 
4154
      if (n++ > 100)
 
4155
        {
 
4156
          cmn_err (CE_WARN, "Audio input %d doesn't get filled.\n",
 
4157
                   adev->engine_num);
 
4158
          cmn_err (CE_CONT, "Counters %d / %d\n", count, lim);
 
4159
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4160
          return OSS_EIO;
 
4161
        }
 
4162
 
 
4163
      tmout = (dmap->fragment_size * OSS_HZ) / dmap->data_rate;
 
4164
      tmout += OSS_HZ / 2;
 
4165
 
 
4166
      if (adev->go == 0)
 
4167
        tmout = 0;
 
4168
 
 
4169
#ifdef DO_TIMINGS
 
4170
      oss_do_timing ("Sleep (in)");
 
4171
      oss_timing_enter (DF_SLEEPREAD);
 
4172
#endif
 
4173
      audio_engines[adev->engine_num]->dmap_in->error = 0;
 
4174
      if (!oss_sleep (adev->in_wq, &dmap->mutex, tmout, &flags, &status))
 
4175
        {
 
4176
#ifdef DO_TIMINGS
 
4177
          oss_do_timing ("Sleep (in) timed out");
 
4178
#endif
 
4179
          adev->timeout_count++;
 
4180
          if (adev->d->adrv_check_input)
 
4181
            {
 
4182
              int err = adev->d->adrv_check_input (adev->engine_num);
 
4183
              if (err == 0)
 
4184
                continue;       /* Retry */
 
4185
              MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4186
              return err;
 
4187
            }
 
4188
          cmn_err (CE_NOTE,
 
4189
                   "Input timed out on audio engine %d (count=%lld)\n",
 
4190
                   adev->engine_num, dmap->byte_counter);
 
4191
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4192
          FMA_EREPORT(adev->osdev, DDI_FM_DEVICE_STALL, NULL, NULL, NULL);
 
4193
          FMA_IMPACT(adev->osdev, DDI_SERVICE_LOST);
 
4194
          return OSS_EIO;
 
4195
        }                       /* Timed out */
 
4196
 
 
4197
#ifdef DO_TIMINGS
 
4198
      oss_timing_leave (DF_SLEEPREAD);
 
4199
      oss_do_timing ("Sleep (in) done");
 
4200
#endif
 
4201
 
 
4202
      if (status & WK_SIGNAL)
 
4203
        {
 
4204
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4205
          return OSS_EINTR;
 
4206
        }
 
4207
      count = (int) (dmap->byte_counter - dmap->user_counter);
 
4208
#ifdef DO_TIMINGS
 
4209
        oss_timing_printf ("User counter %d, byte_counter %d", dmap->user_counter,
 
4210
                 dmap->byte_counter);
 
4211
#endif
 
4212
    }
 
4213
 
 
4214
/* Now we should have some data */
 
4215
 
 
4216
  if (adev->nonblock)
 
4217
    get_input_pointer (adev, dmap, 1);
 
4218
 
 
4219
  offs = dmap->user_counter % dmap->bytes_in_use;
 
4220
  doffs = dmap->byte_counter % dmap->bytes_in_use;
 
4221
 
 
4222
  count = (int) (dmap->bytes_in_use - offs);
 
4223
  if (offs <= doffs)
 
4224
    count = (int) (doffs - offs);
 
4225
  if (count == 0)
 
4226
    count = dmap->bytes_in_use;
 
4227
 
 
4228
  *dmapos = offs;
 
4229
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4230
 
 
4231
  return count;
 
4232
}
 
4233
 
 
4234
/*ARGSUSED*/
 
4235
static int
 
4236
move_raw_rdpointer (adev_p adev, dmap_p dmap, int len)
 
4237
{
 
4238
  int ret = 0;
 
4239
  oss_native_word flags;
 
4240
#ifdef DO_TIMINGS
 
4241
    oss_timing_printf ("Move rdpointer, offs=%d, incr %d", dmap->user_counter,
 
4242
             len);
 
4243
#endif
 
4244
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
4245
  dmap->user_counter += len;
 
4246
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4247
 
 
4248
  return ret;
 
4249
}
 
4250
 
 
4251
static void
 
4252
copy_read_noninterleaved(adev_t *adev, dmap_t *dmap, int dma_offs, unsigned char *localbuf, int local_offs, int l)
 
4253
{
 
4254
/*
 
4255
 * Copy audio data from non-interleaved device buffer to interleaved
 
4256
 * local buffer.
 
4257
 */
 
4258
// TODO: This function assumes 32 bit audio DATA
 
4259
        
 
4260
  int ch, i, nc = adev->hw_parms.channels;
 
4261
  int *outbuf, *inbuf;
 
4262
 
 
4263
  l             /= sizeof(*outbuf)*nc;
 
4264
  dma_offs      /= sizeof(*outbuf);
 
4265
  local_offs    /= sizeof(*outbuf);
 
4266
 
 
4267
  for (ch=0;ch<nc;ch++)
 
4268
  {
 
4269
        outbuf = (int*)(localbuf+local_offs);
 
4270
        outbuf += ch;
 
4271
 
 
4272
        inbuf = (int *)(dmap->dmabuf + dmap->buffsize*ch / nc);
 
4273
        inbuf += dma_offs / nc;
 
4274
 
 
4275
        for (i=0;i<l;i++)
 
4276
        {
 
4277
                *outbuf = *inbuf++;
 
4278
                outbuf += nc;
 
4279
        }
 
4280
  }
 
4281
 
 
4282
}
 
4283
 
 
4284
static int
 
4285
find_input_space (adev_p adev, dmap_p dmap, unsigned char **dbuf)
 
4286
{
 
4287
  unsigned char *p, *p1 = dmap->tmpbuf1, *p2 = dmap->tmpbuf2;
 
4288
  int err, l, l2, max, dmapos;
 
4289
 
 
4290
  if (!(dmap->flags & DMAP_COOKED))
 
4291
    {
 
4292
      err=find_raw_input_space (adev, dmap, &dmapos);
 
4293
      *dbuf=dmap->dmabuf+dmapos;
 
4294
      return err;
 
4295
    }
 
4296
 
 
4297
  if (dmap->tmpbuf_len > dmap->tmpbuf_ptr)
 
4298
    {
 
4299
      *dbuf = dmap->tmpbuf1 + dmap->tmpbuf_ptr;
 
4300
      return dmap->tmpbuf_len - dmap->tmpbuf_ptr;
 
4301
    }
 
4302
 
 
4303
  dmap->tmpbuf_len = dmap->tmpbuf_ptr = 0;
 
4304
 
 
4305
  if ((l = find_raw_input_space (adev, dmap, &dmapos)) < 0)
 
4306
    {
 
4307
      return l;
 
4308
    }
 
4309
  p=dmap->dmabuf;
 
4310
 
 
4311
  if (dmap->expand_factor > UNIT_EXPAND)
 
4312
    max = (TMP_CONVERT_MAX * UNIT_EXPAND) / dmap->expand_factor;
 
4313
  else
 
4314
    max = TMP_CONVERT_MAX;
 
4315
 
 
4316
  if (max > TMP_CONVERT_MAX)
 
4317
    max = TMP_CONVERT_MAX;
 
4318
 
 
4319
  if (l > max)
 
4320
    l = max;
 
4321
  l = (l / dmap->frame_size) * dmap->frame_size;        /* Truncate to nearest frame size */
 
4322
  l2 = l;
 
4323
  VMEM_CHECK (p1, l);
 
4324
  VMEM_CHECK (p+dmapos, l);
 
4325
 
 
4326
  if ((adev->flags & ADEV_NONINTERLEAVED) && adev->hw_parms.channels > 1)
 
4327
     copy_read_noninterleaved(adev, dmap, dmapos, p1, 0, l);
 
4328
  else
 
4329
     memcpy (p1, p+dmapos, l);
 
4330
 
 
4331
  move_raw_rdpointer (adev, dmap, l);
 
4332
 
 
4333
  if ((err =
 
4334
       dmap->convert_func (adev, dmap, &p1, &l2,
 
4335
                           &p2, &adev->hw_parms,
 
4336
                           &adev->user_parms)) < 0)
 
4337
    return err;
 
4338
 
 
4339
  dmap->tmpbuf1 = p1;
 
4340
  dmap->tmpbuf2 = p2;
 
4341
  dmap->tmpbuf_len = l2;
 
4342
 
 
4343
  *dbuf = dmap->tmpbuf1;
 
4344
  return dmap->tmpbuf_len;
 
4345
}
 
4346
 
 
4347
static int
 
4348
move_rdpointer (adev_p adev, dmap_p dmap, int len)
 
4349
{
 
4350
  if (!(dmap->flags & DMAP_COOKED) || dmap->tmpbuf_ptr >= dmap->tmpbuf_len)
 
4351
    {
 
4352
      dmap->tmpbuf_ptr = 0;
 
4353
      dmap->tmpbuf_len = 0;
 
4354
      return move_raw_rdpointer (adev, dmap, len);
 
4355
    }
 
4356
 
 
4357
  if (dmap->tmpbuf_ptr < dmap->tmpbuf_len)
 
4358
    {
 
4359
      dmap->tmpbuf_ptr += len;
 
4360
 
 
4361
      if (dmap->tmpbuf_ptr >= dmap->tmpbuf_len)
 
4362
        dmap->tmpbuf_len = dmap->tmpbuf_ptr = 0;
 
4363
 
 
4364
      return 0;
 
4365
    }
 
4366
 
 
4367
  cmn_err (CE_NOTE, "Why here?\n");
 
4368
  return OSS_EIO;
 
4369
}
 
4370
 
 
4371
int
 
4372
oss_audio_read (int dev, struct fileinfo *file, uio_t * buf, int count)
 
4373
{
 
4374
  adev_p adev;
 
4375
  dmap_p dmap;
 
4376
  int c, l, p, ret, n;
 
4377
  unsigned char *dmabuf;
 
4378
#ifdef DO_TIMINGS
 
4379
    oss_timing_printf ("--- audio_read(%d, %d) ---", dev, count);
 
4380
#endif
 
4381
 
 
4382
  sync_seed++;
 
4383
 
 
4384
  if (dev < 0 || dev >= num_audio_engines)
 
4385
    return OSS_ENXIO;
 
4386
 
 
4387
  adev = audio_engines[dev];
 
4388
  if (!adev->enabled)
 
4389
    return OSS_ENXIO;
 
4390
  if (adev->flags & ADEV_NOINPUT)
 
4391
    return OSS_EACCES;
 
4392
  dmap = adev->dmap_in;
 
4393
 
 
4394
  if (!(adev->open_mode & OPEN_READ))
 
4395
    return OSS_ENOTSUP;
 
4396
  if (dmap->dma_mode == PCM_ENABLE_OUTPUT)
 
4397
    {
 
4398
      audio_reset_output (adev);
 
4399
      reset_dmap (dmap);
 
4400
    }
 
4401
 
 
4402
/*
 
4403
 * Initial setup 
 
4404
 */
 
4405
  oss_reset_wait_queue (adev->in_wq);
 
4406
 
 
4407
  if (file != NULL)
 
4408
    {
 
4409
      if ((ISSET_FILE_FLAG (file, O_NONBLOCK)
 
4410
           && !(adev->open_flags & OF_BLOCK)) || adev->forced_nonblock)
 
4411
        adev->nonblock = 1;
 
4412
      else
 
4413
        adev->nonblock = 0;
 
4414
#ifdef DO_TIMINGS
 
4415
      if (adev->nonblock)
 
4416
        oss_do_timing ("*** NON BLOCKING READ ***");
 
4417
#endif
 
4418
    }
 
4419
 
 
4420
  if (dmap->dma_mode != PCM_ENABLE_INPUT)
 
4421
    {
 
4422
      if ((ret = prepare_input (adev, dmap)) < 0)
 
4423
        {
 
4424
          DDB (cmn_err (CE_CONT, "Prepare input failed, err=%d\n", ret));
 
4425
          return ret;
 
4426
        }
 
4427
      dmap->dma_mode = PCM_ENABLE_INPUT;
 
4428
      launch_input (adev, dmap);
 
4429
    }
 
4430
 
 
4431
  if (!(dmap->flags & DMAP_PREPARED))
 
4432
    {                           /* Not prepared. Why??? */
 
4433
      cmn_err (CE_WARN, "Intenal error (not prepared)\n");
 
4434
      return OSS_EIO;
 
4435
    }
 
4436
 
 
4437
  c = count;
 
4438
  p = 0;
 
4439
  n = 0;
 
4440
 
 
4441
  while (c > 0 && n++ < 1000)
 
4442
    {
 
4443
      if ((l = find_input_space (adev, dmap, &dmabuf)) < 0)
 
4444
        {
 
4445
          if (l == OSS_EINTR)
 
4446
            {
 
4447
              if (c == count)   /* Nothing read yet */
 
4448
                return OSS_EINTR;
 
4449
              return count - c;
 
4450
            }
 
4451
          if (l == OSS_EAGAIN)
 
4452
            {
 
4453
              if (c == count)   /* Nothing read yet */
 
4454
                return OSS_EAGAIN;
 
4455
              return count - c;
 
4456
            }
 
4457
          return l;
 
4458
        }
 
4459
 
 
4460
      if (l > c)
 
4461
        l = c;
 
4462
 
 
4463
      if (uiomove (dmabuf, l, UIO_READ, buf) != 0)
 
4464
        {
 
4465
          cmn_err (CE_WARN, "audio: uiomove(UIO_READ) failed\n");
 
4466
          return OSS_EFAULT;
 
4467
        }
 
4468
      if ((ret = move_rdpointer (adev, dmap, l)) < 0)
 
4469
        {
 
4470
          return ret;
 
4471
        }
 
4472
 
 
4473
      c -= l;
 
4474
      p += l;
 
4475
    }
 
4476
 
 
4477
#ifdef DO_TIMINGS
 
4478
    oss_timing_printf ("-------- Audio read done (%d)", count - c);
 
4479
#endif
 
4480
 
 
4481
  return count - c;
 
4482
}
 
4483
 
 
4484
/*ARGSUSED*/
 
4485
static int
 
4486
audio_space_in_queue (adev_p adev, dmap_p dmap, int count)
 
4487
{
 
4488
  int cnt;
 
4489
 
 
4490
  cnt = (int) (dmap->byte_counter + dmap->bytes_in_use - dmap->user_counter);
 
4491
 
 
4492
  if (cnt < 0)
 
4493
    {
 
4494
      cmn_err (CE_CONT, "Buffer %d overfilled (%d)\n", adev->engine_num, cnt);
 
4495
    }
 
4496
 
 
4497
  if (!(dmap->mapping_flags & DMA_MAP_MAPPED))
 
4498
    if (cnt > dmap->bytes_in_use)       /* Output underrun */
 
4499
      {
 
4500
#ifdef DO_TIMINGS
 
4501
        oss_timing_printf ("adev %d: Play underrun B", adev->engine_num);
 
4502
        oss_timing_printf ("  User=%lld", dmap->user_counter);
 
4503
        oss_timing_printf ("  Dev=%lld", dmap->byte_counter);
 
4504
        oss_timing_printf ("  Tmp=%d", dmap->tmpbuf_ptr);
 
4505
#endif
 
4506
        cnt = dmap->bytes_in_use;
 
4507
        dmap->user_counter = dmap->byte_counter;
 
4508
        dmap->play_underruns++;
 
4509
        if (!dmap->underrun_flag)
 
4510
          {
 
4511
#ifdef DO_TIMINGS
 
4512
            oss_do_timing ("Clearing the buffer");
 
4513
#endif
 
4514
            memset (dmap->dmabuf, dmap->neutral_byte, dmap->bytes_in_use);
 
4515
          }
 
4516
        dmap->underrun_flag = 1;
 
4517
      }
 
4518
 
 
4519
  if ((dmap->user_counter + cnt) > (dmap->byte_counter + dmap->bytes_in_use))
 
4520
    cmn_err (CE_CONT, "Overflow %lld+%d, %lld\n", dmap->user_counter, cnt,
 
4521
             dmap->byte_counter);
 
4522
 
 
4523
  return cnt;
 
4524
}
 
4525
 
 
4526
static int
 
4527
find_output_space (adev_p adev, dmap_p dmap, int *size, int count)
 
4528
{
 
4529
  int offs;
 
4530
  int len, l2, n = 0, tmout;
 
4531
  oss_native_word flags;
 
4532
  int tout;
 
4533
  unsigned int status;
 
4534
 
 
4535
  if (dmap == NULL)
 
4536
    {
 
4537
      cmn_err (CE_WARN, "Internal error - dmap==NULL\n");
 
4538
      return OSS_EIO;
 
4539
    }
 
4540
 
 
4541
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
4542
  len = audio_space_in_queue (adev, dmap, count);
 
4543
 
 
4544
  tout = 0;
 
4545
  while (len < dmap->user_frame_size)
 
4546
    {                           /* Wait for some space */
 
4547
      if (tout++ > 10000)
 
4548
        {
 
4549
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4550
          cmn_err (CE_WARN, "Internal timeout error B\n");
 
4551
          return OSS_EIO;
 
4552
        }
 
4553
 
 
4554
      if (adev->nonblock || !(adev->enable_bits & PCM_ENABLE_OUTPUT))
 
4555
        {
 
4556
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4557
#ifdef DO_TIMINGS
 
4558
            oss_timing_printf ("Space=%d\n", len);
 
4559
            oss_do_timing ("*** EAGAIN ***");
 
4560
#endif
 
4561
          if (!(adev->enable_bits & PCM_ENABLE_OUTPUT))
 
4562
            {
 
4563
              launch_output (adev, dmap);
 
4564
              oss_audio_set_error (adev->engine_num, E_PLAY,
 
4565
                                   OSSERR (1021,
 
4566
                                           "Play buffer full when playback is triggered off."),
 
4567
                                   0);
 
4568
              /*
 
4569
               * Errordesc:
 
4570
               * An application had written too many samples of data between
 
4571
               * turning off the PCM_ENABLE_OUTPUT trigger bit and turning it back
 
4572
               * again to trigger playback.
 
4573
               *
 
4574
               * Applications using SNDCTL_DSP_SETTRIGGER should avoid filling the 
 
4575
               * available playback buffer before triggering output.
 
4576
               *
 
4577
               * One possible error causing this is that the application has
 
4578
               * triggered only recording on a duplex device.
 
4579
               */
 
4580
            }
 
4581
          return OSS_EAGAIN;
 
4582
        }
 
4583
 
 
4584
      if (n++ > dmap->nfrags * 2)
 
4585
        {
 
4586
          cmn_err (CE_WARN, "Audio output %d doesn't drain (%lld/%lld %d).\n",
 
4587
                   adev->engine_num, dmap->user_counter, dmap->byte_counter,
 
4588
                   len);
 
4589
          cmn_err (CE_CONT, "len=%d/%d, total=%d\n", len, dmap->fragment_size,
 
4590
                   dmap->bytes_in_use);
 
4591
#ifdef DO_TIMINGS
 
4592
          oss_do_timing ("Audio output doesn't drain");
 
4593
#endif
 
4594
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4595
          audio_reset_output (adev);
 
4596
          return OSS_EIO;
 
4597
        }
 
4598
 
 
4599
      tmout = (dmap->fragment_size * OSS_HZ) / dmap->data_rate;
 
4600
      tmout += OSS_HZ;
 
4601
 
 
4602
      if (adev->go == 0)
 
4603
        tmout = 0;
 
4604
 
 
4605
      audio_engines[adev->engine_num]->dmap_out->error = 0;
 
4606
      if (adev->go == 0)
 
4607
        {
 
4608
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4609
          return OSS_EAGAIN;
 
4610
        }
 
4611
#ifdef DO_TIMINGS
 
4612
      oss_timing_printf ("Sleep(%d)", adev->engine_num);
 
4613
      oss_timing_enter (DF_SLEEPWRITE);
 
4614
#endif
 
4615
      UP_STATUS (STS_SLEEP);
 
4616
      if (!oss_sleep (adev->out_wq, &dmap->mutex, tmout, &flags, &status))
 
4617
        {
 
4618
#ifdef DO_TIMINGS
 
4619
          oss_timing_printf ("Sleep(%d) (out) timed out", adev->engine_num);
 
4620
#endif
 
4621
          adev->timeout_count++;
 
4622
 
 
4623
          if (adev->d->adrv_check_output)
 
4624
            {
 
4625
              int err = adev->d->adrv_check_output (adev->engine_num);
 
4626
              if (err == 0)
 
4627
                continue;       /* Retry */
 
4628
              MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4629
              return err;
 
4630
            }
 
4631
          else
 
4632
            {
 
4633
              cmn_err (CE_NOTE,
 
4634
                       "Output timed out on audio engine %d/'%s' (count=%lld)\n",
 
4635
                       adev->engine_num, adev->name, dmap->byte_counter);
 
4636
            }
 
4637
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4638
          FMA_EREPORT(adev->osdev, DDI_FM_DEVICE_STALL, NULL, NULL, NULL);
 
4639
          FMA_IMPACT(adev->osdev, DDI_SERVICE_LOST);
 
4640
          return OSS_EIO;
 
4641
        }                       /* Timed out */
 
4642
      DOWN_STATUS (STS_SLEEP);
 
4643
 
 
4644
#ifdef DO_TIMINGS
 
4645
      oss_timing_leave (DF_SLEEPWRITE);
 
4646
      oss_timing_printf ("Sleep(%d) (out) done", adev->engine_num);
 
4647
#endif
 
4648
 
 
4649
      if (status & WK_SIGNAL)
 
4650
        {
 
4651
#ifdef DO_TIMINGS
 
4652
          oss_do_timing ("Signal caught");
 
4653
#endif
 
4654
          MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4655
          return OSS_EINTR;
 
4656
        }
 
4657
 
 
4658
      len = audio_space_in_queue (adev, dmap, count);
 
4659
#ifdef DO_TIMINGS
 
4660
      oss_timing_printf ("Free output space now %d bytes", len);
 
4661
#endif
 
4662
    }                           /* Wait for space */
 
4663
 
 
4664
/*
 
4665
 * Now we hopefully have some free space in the buffer.
 
4666
 */
 
4667
 
 
4668
  offs = (int) (dmap->user_counter % dmap->bytes_in_use);
 
4669
 
 
4670
  l2 = dmap->bytes_in_use - offs;
 
4671
  if (len > l2)
 
4672
    len = l2;
 
4673
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4674
  if (len < 0)
 
4675
    len = 0;
 
4676
 
 
4677
  *size = len;
 
4678
#ifdef DO_TIMINGS
 
4679
  oss_timing_printf ("Got output buffer, offs %d/%d, len %d", offs,
 
4680
             dmap->bytes_in_use, len);
 
4681
#endif
 
4682
  if (offs < 0 || (offs + len) > dmap->bytes_in_use)
 
4683
    {
 
4684
      cmn_err (CE_WARN, "Bad audio output buffer %d/%d\n", offs, len);
 
4685
      return OSS_EIO;
 
4686
    }
 
4687
 
 
4688
  return offs;
 
4689
}
 
4690
 
 
4691
static int
 
4692
launch_output (adev_p adev, dmap_p dmap)
 
4693
{
 
4694
  oss_native_word flags;
 
4695
 
 
4696
#ifdef DO_TIMINGS
 
4697
  oss_do_timing ("Launch output called");
 
4698
#endif
 
4699
  if (dmap->flags & DMAP_STARTED)
 
4700
    {
 
4701
      return 0;
 
4702
    }
 
4703
 
 
4704
  if (dmap->user_counter == 0 && dmap->audio_callback == NULL
 
4705
      && dmap->mapping_flags == 0)
 
4706
    {
 
4707
      return 0;
 
4708
    }
 
4709
 
 
4710
  if (!(dmap->flags & DMAP_PREPARED))
 
4711
    {
 
4712
      cmn_err (CE_WARN, "launch_output while not prepared. Engine=%d\n", adev->engine_num);
 
4713
      return OSS_EIO;
 
4714
    }
 
4715
 
 
4716
#ifdef DO_TIMINGS
 
4717
  oss_do_timing ("Launch_output calling output_block");
 
4718
#endif
 
4719
 
 
4720
  if (adev->d->adrv_output_block != NULL)
 
4721
    {
 
4722
      if (adev->flags & ADEV_AUTOMODE)
 
4723
        adev->d->adrv_output_block (adev->engine_num, dmap->dmabuf_phys,
 
4724
                                    dmap->bytes_in_use, dmap->fragment_size,
 
4725
                                    0);
 
4726
      else
 
4727
        adev->d->adrv_output_block (adev->engine_num, dmap->dmabuf_phys,
 
4728
                                    dmap->fragment_size, dmap->fragment_size,
 
4729
                                    0);
 
4730
    }
 
4731
 
 
4732
#ifdef DO_TIMINGS
 
4733
  oss_do_timing ("Launch_output calling trigger");
 
4734
#endif
 
4735
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
4736
  dmap->flags |= DMAP_STARTED;
 
4737
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4738
  if (adev->d->adrv_trigger
 
4739
      && ((adev->enable_bits * adev->go) & PCM_ENABLE_OUTPUT))
 
4740
    {
 
4741
      adev->d->adrv_trigger (adev->engine_num, adev->enable_bits * adev->go);
 
4742
    }
 
4743
 
 
4744
  return 0;
 
4745
}
 
4746
 
 
4747
static int
 
4748
move_wrpointer (adev_p adev, dmap_p dmap, int len)
 
4749
{
 
4750
  int ret = 0;
 
4751
  oss_native_word flags;
 
4752
#ifdef DO_TIMINGS
 
4753
  oss_timing_printf ("Move wrpointer, len %d", len);
 
4754
#endif
 
4755
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
4756
  dmap->underrun_flag = 0;
 
4757
 
 
4758
  dmap->user_counter += len;
 
4759
#ifdef DO_TIMINGS
 
4760
  oss_timing_printf ("  User=%lld", dmap->user_counter);
 
4761
  oss_timing_printf ("  Byte=%lld", dmap->byte_counter);
 
4762
  oss_timing_printf ("  Fill=%lld", dmap->user_counter - dmap->byte_counter);
 
4763
#endif
 
4764
 
 
4765
#ifdef CONFIG_OSSD
 
4766
  ossd_event (adev->engine_num, OSSD_EV_UPDATE_OUTPUT);
 
4767
#endif
 
4768
 
 
4769
  if (ret < 0 || dmap->flags & DMAP_STARTED)
 
4770
    {
 
4771
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4772
      return ret;
 
4773
    }
 
4774
 
 
4775
  if (!(adev->enable_bits & PCM_ENABLE_OUTPUT))
 
4776
    {
 
4777
#ifdef DO_TIMINGS
 
4778
      oss_do_timing ("Output not triggered - skipping launch_output");
 
4779
#endif
 
4780
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4781
      return ret;
 
4782
    }
 
4783
 
 
4784
  if ((dmap->user_counter < dmap->fragment_size * 2)
 
4785
      && (dmap->user_counter < dmap->bytes_in_use / 2))
 
4786
    {
 
4787
#ifdef DO_TIMINGS
 
4788
      oss_timing_printf ("dmap->user_counter=%lld, dmap->fragment_size*2=%ld",
 
4789
               dmap->user_counter, dmap->fragment_size * 2);
 
4790
      oss_do_timing
 
4791
        ("Not enough data in the buffer yet - skipping launch_output");
 
4792
#endif
 
4793
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4794
      return ret;
 
4795
    }
 
4796
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4797
  ret = launch_output (adev, dmap);
 
4798
  return ret;
 
4799
}
 
4800
 
 
4801
/*ARGSUSED*/
 
4802
static void
 
4803
store_tmp_data (adev_p adev, dmap_p dmap, unsigned char *buf, int count)
 
4804
{
 
4805
  dmap->leftover_buf = buf;
 
4806
  dmap->leftover_bytes = count;
 
4807
}
 
4808
 
 
4809
static void
 
4810
copy_write_noninterleaved(adev_t *adev, dmap_t *dmap, int dma_offs, unsigned char *localbuf, int local_offs, int l)
 
4811
{
 
4812
/*
 
4813
 * Copy interleaved N channel data to non-interleaved device buffer.
 
4814
 */
 
4815
// TODO: This function assumes 32 bit audio DATA
 
4816
        
 
4817
  int ch, i, nc = adev->hw_parms.channels;
 
4818
  int *inbuf, *outbuf;
 
4819
 
 
4820
  l             /= sizeof(*inbuf)*nc;
 
4821
  dma_offs      /= sizeof(*inbuf);
 
4822
  local_offs    /= sizeof(*inbuf);
 
4823
 
 
4824
  for (ch=0;ch<nc;ch++)
 
4825
  {
 
4826
        inbuf = (int*)(localbuf+local_offs);
 
4827
        inbuf += ch;
 
4828
 
 
4829
        outbuf = (int *)(dmap->dmabuf + dmap->buffsize*ch / nc);
 
4830
        outbuf += dma_offs / nc;
 
4831
 
 
4832
        for (i=0;i<l;i++)
 
4833
        {
 
4834
                *outbuf++ = *inbuf;
 
4835
                inbuf += nc;
 
4836
        }
 
4837
  }
 
4838
 
 
4839
}
 
4840
 
 
4841
static int
 
4842
write_copy (adev_p adev, dmap_p dmap, unsigned char *buf, int count)
 
4843
{
 
4844
  int err, offs, spc, l, p = 0;
 
4845
 
 
4846
  while (count)
 
4847
    {
 
4848
      l = count;
 
4849
 
 
4850
      if ((offs = find_output_space (adev, dmap, &spc, l)) < 0)
 
4851
        {
 
4852
          if (offs == OSS_EAGAIN)
 
4853
            {
 
4854
              store_tmp_data (adev, dmap, buf + p, count);
 
4855
              launch_output (adev, dmap);
 
4856
              return OSS_EAGAIN;
 
4857
            }
 
4858
          return offs;
 
4859
        }
 
4860
 
 
4861
      if (l > spc)
 
4862
        l = spc;
 
4863
 
 
4864
      VMEM_CHECK (&dmap->dmabuf[offs], l);
 
4865
      VMEM_CHECK (buf + p, l);
 
4866
 
 
4867
      if ((adev->flags & ADEV_NONINTERLEAVED) && adev->hw_parms.channels > 1)
 
4868
         {
 
4869
            copy_write_noninterleaved(adev, dmap, offs, buf + p, 0, l);
 
4870
         }
 
4871
      else
 
4872
         memcpy (&dmap->dmabuf[offs], buf + p, l);
 
4873
 
 
4874
      if ((err = move_wrpointer (adev, dmap, l)) < 0)
 
4875
        return err;
 
4876
 
 
4877
      count -= l;
 
4878
      p += l;
 
4879
    }
 
4880
  return 0;
 
4881
}
 
4882
 
 
4883
int
 
4884
oss_audio_write (int dev, struct fileinfo *file, uio_t * buf, int count)
 
4885
{
 
4886
  adev_p adev;
 
4887
  oss_native_word flags;
 
4888
  dmap_p dmap;
 
4889
  int ret;
 
4890
  int l, c, spc, offs, p, err;
 
4891
  int tmout;
 
4892
 
 
4893
#ifdef DO_TIMINGS
 
4894
  oss_timing_printf ("--- audio_write(%d, %d) ---", dev, count);
 
4895
#endif
 
4896
 
 
4897
  sync_seed++;
 
4898
 
 
4899
  if (dev < 0 || dev >= num_audio_engines)
 
4900
    return OSS_ENXIO;
 
4901
 
 
4902
  adev = audio_engines[dev];
 
4903
  if (!adev->enabled)
 
4904
    return OSS_ENXIO;
 
4905
  if (adev->flags & ADEV_NOOUTPUT)
 
4906
    return OSS_EACCES;
 
4907
  dmap = adev->dmap_out;
 
4908
 
 
4909
  if (!(adev->open_mode & OPEN_WRITE))
 
4910
    return OSS_ENOTSUP;
 
4911
 
 
4912
  UP_STATUS (STS_WRITE);
 
4913
 
 
4914
  if (dmap->dma_mode == PCM_ENABLE_INPUT)
 
4915
    {
 
4916
      audio_reset_input (adev);
 
4917
      reset_dmap (dmap);
 
4918
    }
 
4919
 
 
4920
/*
 
4921
 * Initial setup 
 
4922
 */
 
4923
  oss_reset_wait_queue (adev->out_wq);
 
4924
 
 
4925
  if (file != NULL)
 
4926
    {
 
4927
      if ((ISSET_FILE_FLAG (file, O_NONBLOCK)
 
4928
           && !(adev->open_flags & OF_BLOCK)) || adev->forced_nonblock)
 
4929
        adev->nonblock = 1;
 
4930
      else
 
4931
        adev->nonblock = 0;
 
4932
#ifdef DO_TIMINGS
 
4933
      if (adev->nonblock)
 
4934
        oss_do_timing ("*** NON BLOCKING WRITE ***");
 
4935
#endif
 
4936
    }
 
4937
 
 
4938
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
4939
 
 
4940
  if (dmap->dma_mode != PCM_ENABLE_OUTPUT)
 
4941
    {
 
4942
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4943
      if ((ret = prepare_output (adev, dmap)) < 0)
 
4944
        {
 
4945
          DOWN_STATUS (STS_WRITE);
 
4946
          return ret;
 
4947
        }
 
4948
      MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
4949
      dmap->dma_mode = PCM_ENABLE_OUTPUT;
 
4950
    }
 
4951
 
 
4952
  if (!(dmap->flags & DMAP_PREPARED))
 
4953
    {                           /* Not prepared. Why??? */
 
4954
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4955
      DOWN_STATUS (STS_WRITE);
 
4956
      cmn_err (CE_WARN, "Internal error (not prepared)\n");
 
4957
      return OSS_EIO;
 
4958
    }
 
4959
#if 1
 
4960
  if (dmap->leftover_bytes > 0)
 
4961
    {
 
4962
      unsigned char *b;
 
4963
      int l;
 
4964
 
 
4965
      b = dmap->leftover_buf;
 
4966
      l = dmap->leftover_bytes;
 
4967
      dmap->leftover_bytes = 0;
 
4968
      dmap->leftover_buf = NULL;
 
4969
 
 
4970
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4971
      if ((err = write_copy (adev, dmap, b, l)) < 0)
 
4972
        {
 
4973
          DOWN_STATUS (STS_WRITE);
 
4974
          return err;
 
4975
        }
 
4976
 
 
4977
      dmap->leftover_bytes = 0;
 
4978
      dmap->leftover_buf = NULL;
 
4979
      MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
4980
    }
 
4981
#endif
 
4982
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
4983
 
 
4984
  if (count <= 0)
 
4985
    {
 
4986
      DOWN_STATUS (STS_WRITE);
 
4987
      return 0;
 
4988
    }
 
4989
 
 
4990
  c = count;
 
4991
  p = 0;
 
4992
 
 
4993
  tmout = 0;
 
4994
 
 
4995
  while (c > 0)
 
4996
    {
 
4997
#ifdef DO_TIMINGS
 
4998
        oss_timing_printf ("%d/%d bytes to go", c, count);
 
4999
#endif
 
5000
 
 
5001
      if (tmout++ > 1000)
 
5002
        {
 
5003
          cmn_err (CE_WARN, "Internal timeout error A (%d/%d)\n", c, count);
 
5004
          return OSS_EIO;
 
5005
        }
 
5006
 
 
5007
      l = c;
 
5008
      if (l > 8)
 
5009
        l &= ~7;                /* Align it */
 
5010
 
 
5011
      if ((offs = find_output_space (adev, dmap, &spc, l)) < 0)
 
5012
        {
 
5013
          if (offs == OSS_EINTR)
 
5014
            {
 
5015
              DOWN_STATUS (STS_WRITE);
 
5016
              if (c == count)   /* Nothing written yet */
 
5017
                return OSS_EINTR;
 
5018
              return count - c;
 
5019
            }
 
5020
          if (offs == OSS_EAGAIN)
 
5021
            {
 
5022
              DOWN_STATUS (STS_WRITE);
 
5023
              if (c == count)   /* Nothing written yet */
 
5024
                {
 
5025
                  return OSS_EAGAIN;
 
5026
                }
 
5027
              return count - c;
 
5028
            }
 
5029
          DOWN_STATUS (STS_WRITE);
 
5030
          return offs;
 
5031
        }
 
5032
 
 
5033
      if (dmap->convert_func == NULL)
 
5034
        {
 
5035
          if (dmap->device_write != NULL)
 
5036
            {
 
5037
              unsigned char *tmpbuf;
 
5038
              int l2;
 
5039
 
 
5040
              if (dmap->tmpbuf1 == NULL)
 
5041
                {
 
5042
                  dmap->tmpbuf1 = AUDIO_MALLOC (dmap->osdev, TMP_CONVERT_BUF_SIZE+512);
 
5043
                }
 
5044
 
 
5045
/*
 
5046
 * Leave some room for data expansion so use just half of the available
 
5047
 * space.
 
5048
 */
 
5049
              tmpbuf = dmap->tmpbuf1;
 
5050
              if (l > spc / 2)
 
5051
                l = spc / 2;
 
5052
              if (l > TMP_CONVERT_BUF_SIZE / 2)
 
5053
                l = TMP_CONVERT_BUF_SIZE / 2;
 
5054
 
 
5055
              l2 = l;
 
5056
              if (uiomove (tmpbuf, l, UIO_WRITE, buf) != 0)
 
5057
                {
 
5058
                  cmn_err (CE_WARN,
 
5059
                           "audio: uiomove(UIO_WRITE) failed (noconv)\n");
 
5060
                  DOWN_STATUS (STS_WRITE);
 
5061
                  return OSS_EFAULT;
 
5062
                }
 
5063
              if ((err =
 
5064
                   dmap->device_write (adev, dmap, tmpbuf,
 
5065
                                       &dmap->dmabuf[offs], spc, &l,
 
5066
                                       &l2)) < 0)
 
5067
                {
 
5068
                  DOWN_STATUS (STS_WRITE);
 
5069
                  return err;
 
5070
                }
 
5071
              if ((err = move_wrpointer (adev, dmap, l2)) < 0)
 
5072
                {
 
5073
                  DOWN_STATUS (STS_WRITE);
 
5074
                  return err;
 
5075
                }
 
5076
            }
 
5077
          else
 
5078
            {
 
5079
              if (l > spc)
 
5080
                l = spc;
 
5081
              if (uiomove (&dmap->dmabuf[offs], l, UIO_WRITE, buf) != 0)
 
5082
                {
 
5083
                  cmn_err (CE_WARN,
 
5084
                           "audio: uiomove(UIO_WRITE) (noconv2) failed\n");
 
5085
                  return OSS_EFAULT;
 
5086
                }
 
5087
              if ((err = move_wrpointer (adev, dmap, l)) < 0)
 
5088
                {
 
5089
                  DOWN_STATUS (STS_WRITE);
 
5090
                  return err;
 
5091
                }
 
5092
            }
 
5093
        }
 
5094
      else
 
5095
        {
 
5096
          /*
 
5097
           * Perform format conversions.
 
5098
           */
 
5099
          unsigned char *p1 = dmap->tmpbuf1, *p2 = dmap->tmpbuf2;
 
5100
          int l2, max, out_max;
 
5101
 
 
5102
          if (spc > TMP_CONVERT_MAX)
 
5103
            spc = TMP_CONVERT_MAX / 2;
 
5104
 
 
5105
          if (dmap->expand_factor > UNIT_EXPAND)
 
5106
             {
 
5107
                max = spc;
 
5108
 
 
5109
                out_max = (spc * dmap->expand_factor) / UNIT_EXPAND; /* Output size */
 
5110
                if (out_max > TMP_CONVERT_BUF_SIZE) /* Potential overflow */
 
5111
                   {
 
5112
                           max = (TMP_CONVERT_BUF_SIZE * UNIT_EXPAND) / dmap->expand_factor;
 
5113
                   }
 
5114
             }
 
5115
          else
 
5116
            max = spc;
 
5117
          if (max < dmap->frame_size)
 
5118
            max = dmap->frame_size;
 
5119
 
 
5120
          if (max > TMP_CONVERT_MAX)
 
5121
            max = TMP_CONVERT_MAX / 2;
 
5122
 
 
5123
          if (l > max)
 
5124
            l = max;
 
5125
          /* Avoid leaving too short "tails" */
 
5126
          if (c - l < 64)
 
5127
            l = c;
 
5128
 
 
5129
          /* Round to integer number of samples */
 
5130
          l =
 
5131
            (((l + dmap->frame_size -
 
5132
               1) / dmap->frame_size)) * dmap->frame_size;
 
5133
          if (l > c)
 
5134
            l = c;
 
5135
 
 
5136
          l2 = l;
 
5137
 
 
5138
          VMEM_CHECK (p1, l);
 
5139
          if (uiomove (p1, l, UIO_WRITE, buf) != 0)
 
5140
            cmn_err (CE_WARN, "audio: uiomove(UIO_WRITE) (conv) failed\n");
 
5141
          UP_STATUS (STS_CONVERT);
 
5142
          if ((err =
 
5143
               dmap->convert_func (adev, dmap, &p1, &l2,
 
5144
                                   &p2, &adev->user_parms,
 
5145
                                   &adev->hw_parms)) < 0)
 
5146
            {
 
5147
              cmn_err (CE_WARN, "Format conversion failed (%d)\n", err);
 
5148
              DOWN_STATUS (STS_WRITE | STS_CONVERT);
 
5149
              return err;
 
5150
            }
 
5151
          DOWN_STATUS (STS_CONVERT);
 
5152
 
 
5153
          if ((err = write_copy (adev, dmap, p1, l2)) < 0)
 
5154
            {
 
5155
              if (err != OSS_EAGAIN)
 
5156
                {
 
5157
                  DOWN_STATUS (STS_WRITE);
 
5158
                  return err;
 
5159
                }
 
5160
 
 
5161
              /* Handle non blocking I/O */
 
5162
              if (c == count)   /* Nothing written yet */
 
5163
                {
 
5164
                  DOWN_STATUS (STS_WRITE);
 
5165
                  return OSS_EAGAIN;
 
5166
                }
 
5167
 
 
5168
              DOWN_STATUS (STS_WRITE);
 
5169
              return count - c;
 
5170
 
 
5171
            }
 
5172
        }
 
5173
 
 
5174
      c -= l;
 
5175
      p += l;
 
5176
 
 
5177
      if (l > 0)
 
5178
        tmout = 0;
 
5179
    }
 
5180
 
 
5181
#ifdef DO_TIMINGS
 
5182
  oss_do_timing ("--- Audio write done");
 
5183
#endif
 
5184
  DOWN_STATUS (STS_WRITE);
 
5185
  return count - c;
 
5186
}
 
5187
 
 
5188
#ifdef MANAGE_DEV_DSP
 
5189
#ifdef VDEV_SUPPORT
 
5190
void
 
5191
oss_combine_write_lists (void)
 
5192
{
 
5193
  int i;
 
5194
 
 
5195
  for (i = 0; i < dspoutlist2.ndevs; i++)
 
5196
    dspoutlist.devices[dspoutlist.ndevs++] = dspoutlist2.devices[i];
 
5197
 
 
5198
  dspoutlist2.ndevs = 0;
 
5199
}
 
5200
 
 
5201
/*ARGSUSED*/
 
5202
int
 
5203
oss_open_vdsp (int dev, int dev_type, struct fileinfo *file, int recursive,
 
5204
               int open_flags, int *newdev)
 
5205
{
 
5206
  int ret, i, d;
 
5207
  int mode = file->mode & O_ACCMODE;
 
5208
 
 
5209
  DDB (cmn_err (CE_CONT, "oss_open_vdsp(%d, mode=%d)\n", dev, mode));
 
5210
 
 
5211
  switch (dev)
 
5212
    {
 
5213
    case 1:
 
5214
      mode = OPEN_READ;
 
5215
      break;
 
5216
    case 2:
 
5217
      mode = OPEN_WRITE;
 
5218
      break;
 
5219
 
 
5220
      /* default: Use the mode defined by O_ACCMODE */
 
5221
    }
 
5222
 
 
5223
  dev = -1;
 
5224
  open_flags = get_open_flags (mode, open_flags, file);
 
5225
 
 
5226
  switch (dev_type)
 
5227
    {
 
5228
    case OSS_DEV_VDSP:
 
5229
      dev_type = OSS_DEV_DSP;
 
5230
      break;
 
5231
#if 0
 
5232
    case OSS_DEV_VAUDIO:
 
5233
      dev_type = OSS_DEV_DEVAUDIO;
 
5234
      break;
 
5235
#endif
 
5236
    default:
 
5237
      cmn_err (CE_NOTE, "Unknown dev class %d\n", dev_type);
 
5238
      break;
 
5239
    }
 
5240
 
 
5241
  if (audio_devfiles == NULL)
 
5242
    {
 
5243
      cmn_err (CE_NOTE, "No audio device files available\n");
 
5244
      return OSS_ENXIO;
 
5245
    }
 
5246
#ifdef MANAGE_DEV_DSP
 
5247
#ifdef VDEV_SUPPORT
 
5248
  oss_combine_write_lists ();
 
5249
#endif
 
5250
#endif
 
5251
 
 
5252
#ifdef APPLIST_SUPPORT
 
5253
  {
 
5254
    char *appname;
 
5255
    appname = GET_PROCESS_NAME (file);
 
5256
    if (open_flags & OF_DEVAUDIO)
 
5257
      appname = "Devaudio_Support";
 
5258
 
 
5259
    if ((dev = app_lookup (mode, appname, &open_flags)) >= 0)
 
5260
      if (audio_devfiles[dev]->enabled && !audio_devfiles[dev]->unloaded)
 
5261
        if ((ret =
 
5262
             oss_audio_open_devfile (dev, dev_type, file, 0, open_flags,
 
5263
                                     newdev)) >= 0)
 
5264
          {
 
5265
            dev = ret;
 
5266
            DDB (cmn_err
 
5267
                 (CE_CONT, "Using dsp%d configured for this application\n",
 
5268
                  dev));
 
5269
            goto done;
 
5270
          }
 
5271
  }
 
5272
#endif
 
5273
  DDB (cmn_err (CE_CONT, "\n"));
 
5274
  DDB (cmn_err (CE_CONT, "Out devs: "));
 
5275
  for (i = 0; i < dspoutlist.ndevs; i++)
 
5276
    DDB (cmn_err (CE_CONT, "%d ", dspoutlist.devices[i]));
 
5277
  for (i = 0; i < dspoutlist2.ndevs; i++)
 
5278
    DDB (cmn_err (CE_CONT, "(%d) ", dspoutlist2.devices[i]));
 
5279
  DDB (cmn_err (CE_CONT, "\n"));
 
5280
  DDB (cmn_err (CE_CONT, "In devs: "));
 
5281
  for (i = 0; i < dspinlist.ndevs; i++)
 
5282
    DDB (cmn_err (CE_CONT, "%d ", dspinlist.devices[i]));
 
5283
  DDB (cmn_err (CE_CONT, "\n"));
 
5284
  DDB (cmn_err (CE_CONT, "In/out devs: "));
 
5285
  for (i = 0; i < dspinoutlist.ndevs; i++)
 
5286
    DDB (cmn_err (CE_CONT, "%d ", dspinoutlist.devices[i]));
 
5287
  DDB (cmn_err (CE_CONT, "\n"));
 
5288
 
 
5289
  switch (mode & (OPEN_READ | OPEN_WRITE))
 
5290
    {
 
5291
    case OPEN_WRITE:
 
5292
      DDB (cmn_err (CE_CONT, "Selecting output device: "));
 
5293
 
 
5294
      for (i = 0; i < dspoutlist.ndevs; i++)
 
5295
        {
 
5296
          dev = dspoutlist.devices[i];
 
5297
          if (!audio_devfiles[dev]->enabled || audio_devfiles[dev]->unloaded)
 
5298
            {
 
5299
              dev = -1;
 
5300
              continue;
 
5301
            }
 
5302
 
 
5303
          DDB (cmn_err (CE_CONT, "%d ", dev));
 
5304
          if ((ret =
 
5305
               oss_audio_open_devfile (dev, dev_type, file, 0, open_flags,
 
5306
                                       newdev)) >= 0)
 
5307
            {
 
5308
              dev = ret;
 
5309
              DDB (cmn_err (CE_CONT, "->%d ", dev));
 
5310
              break;
 
5311
            }
 
5312
          dev = -1;
 
5313
        }
 
5314
      break;
 
5315
 
 
5316
    case OPEN_READ:
 
5317
      DDB (cmn_err (CE_CONT, "Selecting input device: "));
 
5318
      for (i = 0; i < dspinlist.ndevs; i++)
 
5319
        {
 
5320
          dev = dspinlist.devices[i];
 
5321
          if (!audio_devfiles[dev]->enabled || audio_devfiles[dev]->unloaded)
 
5322
            {
 
5323
              dev = -1;
 
5324
              continue;
 
5325
            }
 
5326
          DDB (cmn_err (CE_CONT, "%d ", dev));
 
5327
          if ((ret =
 
5328
               oss_audio_open_devfile (dev, dev_type, file, 0, open_flags,
 
5329
                                       newdev)) >= 0)
 
5330
            {
 
5331
              dev = ret;
 
5332
              DDB (cmn_err (CE_CONT, "->%d ", dev));
 
5333
              break;
 
5334
            }
 
5335
 
 
5336
          dev = -1;
 
5337
        }
 
5338
      break;
 
5339
 
 
5340
    case OPEN_WRITE | OPEN_READ:
 
5341
      DDB (cmn_err (CE_CONT, "Selecting input/output device: "));
 
5342
      for (i = 0; i < dspinoutlist.ndevs; i++)
 
5343
        {
 
5344
          dev = dspinoutlist.devices[i];
 
5345
          if (!audio_devfiles[dev]->enabled || audio_devfiles[dev]->unloaded)
 
5346
            {
 
5347
              dev = -1;
 
5348
              continue;
 
5349
            }
 
5350
          DDB (cmn_err (CE_CONT, "%d ", dev));
 
5351
          if ((ret =
 
5352
               oss_audio_open_devfile (dev, dev_type, file, 0, open_flags,
 
5353
                                       newdev)) >= 0)
 
5354
            {
 
5355
              dev = ret;
 
5356
              DDB (cmn_err (CE_CONT, "->%d ", dev));
 
5357
              break;
 
5358
            }
 
5359
          dev = -1;
 
5360
        }
 
5361
      break;
 
5362
    }
 
5363
 
 
5364
  DDB (cmn_err (CE_CONT, " - got vdsp -> %d\n", dev));
 
5365
  if (dev == -1)
 
5366
    return OSS_EBUSY;
 
5367
 
 
5368
done:
 
5369
/*
 
5370
 * Try to find which minor number matches this /dev/dsp# device. Note that the actual
 
5371
 * device type doesn't matter after this point so we can use OSS_DEV_DSP.
 
5372
 */
 
5373
  if ((d = oss_find_minor (OSS_DEV_DSP_ENGINE, dev)) < 0)
 
5374
    {
 
5375
      oss_audio_release (dev, file);
 
5376
      return d;
 
5377
    }
 
5378
 
 
5379
  *newdev = d;
 
5380
  return dev;
 
5381
}
 
5382
#endif
 
5383
#endif
 
5384
 
 
5385
static int
 
5386
audio_init_device (int dev)
 
5387
{
 
5388
  adev_p adev;
 
5389
 
 
5390
  sync_seed = GET_JIFFIES ();
 
5391
  adev = audio_engines[dev];
 
5392
 
 
5393
  MUTEX_INIT (adev->master_osdev, adev->mutex, MH_FRAMEW);
 
5394
 
 
5395
  if (audio_engines[dev]->dmap_out == NULL
 
5396
      || audio_engines[dev]->dmap_in == NULL)
 
5397
    {
 
5398
      dmap_p dmap;
 
5399
 
 
5400
      dmap = AUDIO_MALLOC (adev->osdev, sizeof (dmap_t));
 
5401
      if (dmap == NULL)
 
5402
        {
 
5403
          cmn_err (CE_WARN, "Failed to allocate dmap, dev=%d\n", dev);
 
5404
          return OSS_ENOMEM;
 
5405
        }
 
5406
 
 
5407
      memset ((char *) dmap, 0, sizeof (dmap_t));
 
5408
 
 
5409
      if (!(adev->flags & ADEV_NOOUTPUT) && adev->out_wq == NULL)
 
5410
        {
 
5411
          if ((adev->out_wq =
 
5412
               oss_create_wait_queue (adev->osdev, "audio_out")) == NULL)
 
5413
            {
 
5414
              cmn_err (CE_WARN, "Cannot create audio output wait queue\n");
 
5415
              return OSS_ENOMEM;
 
5416
            }
 
5417
        }
 
5418
 
 
5419
      if (!(adev->flags & ADEV_NOINPUT) && adev->in_wq == NULL)
 
5420
        {
 
5421
          if ((adev->in_wq =
 
5422
               oss_create_wait_queue (adev->osdev, "audio_in")) == NULL)
 
5423
            {
 
5424
              cmn_err (CE_WARN, "Cannot create audio input wait queue\n");
 
5425
              return OSS_ENOMEM;
 
5426
            }
 
5427
        }
 
5428
 
 
5429
      memset ((char *) dmap, 0, sizeof (dmap_t));
 
5430
      dmap->osdev = adev->osdev;
 
5431
      dmap->adev = adev;
 
5432
      dmap->master_osdev = adev->master_osdev;
 
5433
      MUTEX_INIT (dmap->master_osdev, dmap->mutex, MH_FRAMEW + 1);
 
5434
      adev->dmap_out = adev->dmap_in = dmap;
 
5435
 
 
5436
      if (adev->flags & ADEV_DUPLEX)
 
5437
        {
 
5438
 
 
5439
          dmap = AUDIO_MALLOC (adev->osdev, sizeof (dmap_t));
 
5440
          if (dmap == NULL)
 
5441
            {
 
5442
              cmn_err (CE_WARN, "Failed to allocate dmap, dev=%d\n", dev);
 
5443
              return OSS_ENOMEM;
 
5444
            }
 
5445
 
 
5446
          memset ((char *) dmap, 0, sizeof (dmap_t));
 
5447
          dmap->osdev = adev->osdev;
 
5448
          dmap->adev = adev;
 
5449
          dmap->master_osdev = adev->master_osdev;
 
5450
          MUTEX_INIT (dmap->master_osdev, dmap->mutex, MH_FRAMEW + 1);
 
5451
          adev->dmap_in = dmap;
 
5452
        }
 
5453
    }
 
5454
 
 
5455
  return 0;
 
5456
}
 
5457
 
 
5458
void
 
5459
audio_uninit_device (int dev)
 
5460
{
 
5461
  adev_p adev;
 
5462
  /* oss_native_word flags; */
 
5463
 
 
5464
  adev = audio_engines[dev];
 
5465
 
 
5466
  if (adev->unloaded)
 
5467
    return;
 
5468
 
 
5469
  if (adev->dmap_out != NULL && adev->dmap_out->dmabuf != NULL)
 
5470
    {
 
5471
      if (adev->d->adrv_free_buffer != NULL)
 
5472
        {
 
5473
          adev->d->adrv_free_buffer (dev, adev->dmap_out, OPEN_WRITE);
 
5474
        }
 
5475
      else
 
5476
        default_free_buffer (dev, adev->dmap_out, OPEN_WRITE);
 
5477
      adev->dmap_out->dmabuf = NULL;
 
5478
    }
 
5479
 
 
5480
  if (adev->dmap_in != NULL
 
5481
      && (adev->dmap_in != adev->dmap_out && adev->dmap_in->dmabuf != NULL))
 
5482
    {
 
5483
      if (adev->d->adrv_free_buffer != NULL)
 
5484
        {
 
5485
          adev->d->adrv_free_buffer (dev, adev->dmap_in, OPEN_READ);
 
5486
        }
 
5487
      else
 
5488
        default_free_buffer (dev, adev->dmap_in, OPEN_READ);
 
5489
      adev->dmap_in->dmabuf = NULL;
 
5490
    }
 
5491
 
 
5492
  if (adev->in_wq != NULL)
 
5493
    {
 
5494
      oss_remove_wait_queue (adev->in_wq);
 
5495
      adev->in_wq = NULL;
 
5496
    }
 
5497
  if (adev->out_wq != NULL)
 
5498
    {
 
5499
      oss_remove_wait_queue (adev->out_wq);
 
5500
      adev->out_wq = NULL;
 
5501
    }
 
5502
 
 
5503
#ifdef CONFIG_OSS_VMIX
 
5504
  if (adev->vmix_mixer != NULL)
 
5505
     {
 
5506
             adev->vmix_mixer = NULL;
 
5507
     }
 
5508
#endif
 
5509
 
 
5510
  MUTEX_CLEANUP (adev->mutex);
 
5511
 
 
5512
  if (adev->dmap_out != NULL)
 
5513
    MUTEX_CLEANUP (adev->dmap_out->mutex);
 
5514
 
 
5515
  if (adev->flags & ADEV_DUPLEX && adev->dmap_in != NULL
 
5516
      && adev->dmap_out != adev->dmap_in)
 
5517
    {
 
5518
      MUTEX_CLEANUP (adev->dmap_in->mutex);
 
5519
    }
 
5520
  adev->unloaded = 1;
 
5521
}
 
5522
 
 
5523
void
 
5524
oss_audio_init (oss_device_t *osdev)
 
5525
{
 
5526
        MUTEX_INIT (osdev, audio_global_mutex, MH_DRV);
 
5527
}
 
5528
 
 
5529
void
 
5530
oss_audio_uninit (void)
 
5531
{
 
5532
/*
 
5533
 * Release all memory/resources allocated by the audio core.
 
5534
 */
 
5535
  oss_memblk_unalloc(&audio_global_memblk);
 
5536
 
 
5537
  MUTEX_CLEANUP (audio_global_mutex);
 
5538
}
 
5539
 
 
5540
void
 
5541
oss_audio_inc_byte_counter (dmap_t * dmap, int increment)
 
5542
{
 
5543
  oss_uint64_t p1, p2;
 
5544
  oss_native_word flags;
 
5545
 
 
5546
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
5547
  p1 = dmap->byte_counter / dmap->fragment_size;
 
5548
  dmap->byte_counter += increment;
 
5549
  p2 = dmap->byte_counter / dmap->fragment_size;
 
5550
 
 
5551
  dmap->interrupt_count += (int) (p2 - p1);
 
5552
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
5553
}
 
5554
 
 
5555
static void
 
5556
do_inputintr (int dev, int intr_flags)
 
5557
{
 
5558
  adev_p adev;
 
5559
  dmap_p dmap;
 
5560
  int cptr;
 
5561
  oss_native_word flags;
 
5562
 
 
5563
  adev = audio_engines[dev];
 
5564
  dmap = adev->dmap_in;
 
5565
 
 
5566
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
5567
 
 
5568
  if (!(intr_flags & AINTR_NO_POINTER_UPDATES))
 
5569
    {
 
5570
      dmap->byte_counter += dmap->fragment_size;
 
5571
      dmap->interrupt_count++;
 
5572
    }
 
5573
 
 
5574
  while (dmap->byte_counter > dmap->user_counter &&
 
5575
         (int) (dmap->byte_counter - dmap->user_counter) > dmap->bytes_in_use)
 
5576
    {
 
5577
      dmap->user_counter += dmap->fragment_size;
 
5578
      dmap->rec_overruns++;
 
5579
    }
 
5580
  dmap->fragment_counter = (dmap->fragment_counter + 1) % dmap->nfrags;
 
5581
 
 
5582
  if (dmap->dmabuf_dma_handle != NULL) /* Some drivers don't use DMA */
 
5583
     OSS_DMA_SYNC(dmap->dmabuf_dma_handle, 0, dmap->bytes_in_use, OSS_DMA_SYNC_INBOUND);
 
5584
 
 
5585
#ifdef DO_TIMINGS
 
5586
  oss_do_timing ("Wake up (in)");
 
5587
#endif
 
5588
  oss_wakeup (adev->in_wq, &dmap->mutex, &flags, POLLIN | POLLRDNORM);
 
5589
 
 
5590
  if (adev->flags & ADEV_AUTOMODE)
 
5591
    {
 
5592
      goto finish;
 
5593
    }
 
5594
 
 
5595
  cptr = dmap_get_qtail (dmap) * dmap->fragment_size;
 
5596
  if (adev->d->adrv_start_input != NULL)
 
5597
    adev->d->adrv_start_input (adev->engine_num, dmap->dmabuf_phys + cptr,
 
5598
                               dmap->fragment_size, dmap->fragment_size, 1);
 
5599
finish:
 
5600
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
5601
 
 
5602
  if (dmap->audio_callback != NULL)
 
5603
    dmap->audio_callback (adev->engine_num, dmap->callback_parm);
 
5604
}
 
5605
 
 
5606
static void
 
5607
audio_inputintr (int dev, int intr_flags)
 
5608
{
 
5609
  adev_p adev;
 
5610
  dmap_p dmap;
 
5611
  int n;
 
5612
  oss_uint64_t pos;
 
5613
 
 
5614
  if (dev < 0 || dev >= num_audio_engines)
 
5615
    return;
 
5616
 
 
5617
  adev = audio_engines[dev];
 
5618
  dmap = adev->dmap_in;
 
5619
 
 
5620
  if (dmap->dma_mode != PCM_ENABLE_INPUT)
 
5621
    {
 
5622
      return;
 
5623
    }
 
5624
 
 
5625
  if (!(dmap->flags & DMAP_STARTED))
 
5626
    {
 
5627
      return;
 
5628
    }
 
5629
#ifdef DO_TIMINGS
 
5630
  oss_timing_printf ("Inputintr(%d)", dev);
 
5631
#endif
 
5632
 
 
5633
  if (adev->d->adrv_get_input_pointer == NULL
 
5634
      || (intr_flags & AINTR_NO_POINTER_UPDATES))
 
5635
    {
 
5636
      do_inputintr (dev, intr_flags);
 
5637
      return;
 
5638
    }
 
5639
 
 
5640
  pos =
 
5641
    adev->d->adrv_get_input_pointer (adev->engine_num, dmap,
 
5642
                                     PCM_ENABLE_INPUT) / dmap->fragment_size;
 
5643
  n = 0;
 
5644
 
 
5645
  while (dmap_get_qtail (dmap) != pos && n++ < dmap->nfrags)
 
5646
    {
 
5647
      do_inputintr (dev, intr_flags);
 
5648
    }
 
5649
}
 
5650
 
 
5651
static void
 
5652
finish_output_interrupt (adev_p adev, dmap_p dmap)
 
5653
{
 
5654
  if (dmap->dmabuf_dma_handle != NULL) /* Some drivers don't use DMA */
 
5655
     OSS_DMA_SYNC(dmap->dmabuf_dma_handle, 0, dmap->bytes_in_use, OSS_DMA_SYNC_OUTBOUND);
 
5656
 
 
5657
#ifdef CONFIG_OSSD
 
5658
  ossd_event (adev->engine_num, OSSD_EV_UPDATE_OUTPUT);
 
5659
#endif
 
5660
  if (dmap->audio_callback != NULL)
 
5661
    {
 
5662
      dmap->audio_callback (adev->engine_num, dmap->callback_parm);
 
5663
    }
 
5664
}
 
5665
 
 
5666
static void
 
5667
do_outputintr (int dev, int intr_flags)
 
5668
{
 
5669
  adev_p adev;
 
5670
  dmap_p dmap;
 
5671
  int cptr;
 
5672
  oss_native_word flags;
 
5673
 
 
5674
  adev = audio_engines[dev];
 
5675
  dmap = adev->dmap_out;
 
5676
 
 
5677
  MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
5678
 
 
5679
  if (dmap->dmabuf == NULL)
 
5680
    {
 
5681
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
5682
      cmn_err (CE_WARN, "Output interrupt when no buffer is allocated\n");
 
5683
      return;
 
5684
    }
 
5685
 
 
5686
  if (!(intr_flags & AINTR_NO_POINTER_UPDATES))
 
5687
    {
 
5688
      dmap->byte_counter += dmap->fragment_size;
 
5689
      dmap->interrupt_count++;
 
5690
    }
 
5691
 
 
5692
  dmap->fragment_counter = (dmap->fragment_counter + 1) % dmap->nfrags;
 
5693
 
 
5694
  if (dmap->user_counter <= dmap->byte_counter) /* Underrun */
 
5695
    {
 
5696
      if (!(dmap->mapping_flags & DMA_MAP_MAPPED))
 
5697
        {
 
5698
#ifdef DO_TIMINGS
 
5699
          oss_timing_printf ("adev %d: Play underrun A", dev);
 
5700
          oss_timing_printf ("  User=%lld", dmap->user_counter);
 
5701
          oss_timing_printf ("  Dev=%lld", dmap->byte_counter);
 
5702
          oss_timing_printf ("  Tmp=%d", dmap->tmpbuf_ptr);
 
5703
#endif
 
5704
          dmap->play_underruns++;
 
5705
 
 
5706
          if (!dmap->underrun_flag)
 
5707
            {
 
5708
#ifdef DO_TIMINGS
 
5709
              oss_do_timing ("Clearing the buffer");
 
5710
#endif
 
5711
              memset (dmap->dmabuf, dmap->neutral_byte, dmap->buffsize);
 
5712
            }
 
5713
          dmap->underrun_flag = 1;
 
5714
#if 1
 
5715
          dmap->user_counter = dmap->byte_counter + dmap->fragment_size;
 
5716
#endif
 
5717
        }
 
5718
    }
 
5719
 
 
5720
  if (audio_space_in_queue (adev, dmap, 0) >= 0 || adev->nonblock)
 
5721
    {
 
5722
#ifdef DO_TIMINGS
 
5723
      oss_do_timing ("Wake up (out)");
 
5724
#endif
 
5725
      oss_wakeup (adev->out_wq, &dmap->mutex, &flags, POLLOUT | POLLWRNORM);
 
5726
    }
 
5727
 
 
5728
  if (adev->flags & ADEV_AUTOMODE)
 
5729
    {
 
5730
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
5731
      finish_output_interrupt (adev, dmap);
 
5732
      return;
 
5733
    }
 
5734
 
 
5735
  cptr = dmap_get_qhead (dmap) * dmap->fragment_size;
 
5736
  MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
5737
  if (adev->d->adrv_output_block != NULL)
 
5738
    {
 
5739
      adev->d->adrv_output_block (adev->engine_num, dmap->dmabuf_phys + cptr,
 
5740
                                  dmap->fragment_size, dmap->fragment_size,
 
5741
                                  1);
 
5742
    }
 
5743
  finish_output_interrupt (adev, dmap);
 
5744
}
 
5745
 
 
5746
static void
 
5747
audio_outputintr (int dev, int intr_flags)
 
5748
{
 
5749
  adev_p adev;
 
5750
  dmap_p dmap;
 
5751
  int n;
 
5752
  oss_uint64_t pos;
 
5753
 
 
5754
  if (dev < 0 || dev >= num_audio_engines)
 
5755
    return;
 
5756
 
 
5757
  adev = audio_engines[dev];
 
5758
  dmap = adev->dmap_out;
 
5759
 
 
5760
  if (dmap->dma_mode != PCM_ENABLE_OUTPUT)
 
5761
    {
 
5762
      return;
 
5763
    }
 
5764
 
 
5765
  if (!(dmap->flags & DMAP_STARTED))
 
5766
    {
 
5767
      return;
 
5768
    }
 
5769
 
 
5770
#ifdef DO_TIMINGS
 
5771
  oss_timing_printf ("Outputintr(%d)", dev);
 
5772
#endif
 
5773
  UP_STATUS (STS_INTR);
 
5774
 
 
5775
  if (adev->d->adrv_get_output_pointer == NULL
 
5776
      || (intr_flags & AINTR_NO_POINTER_UPDATES))
 
5777
    {
 
5778
      UP_STATUS (STS_DOINTR);
 
5779
      do_outputintr (dev, intr_flags);
 
5780
      DOWN_STATUS (STS_DOINTR | STS_INTR);
 
5781
      return;
 
5782
    }
 
5783
 
 
5784
  pos = get_output_pointer (adev, dmap, 0) / dmap->fragment_size;
 
5785
  n = 0;
 
5786
 
 
5787
  while (dmap_get_qhead (dmap) != pos && n++ < dmap->nfrags)
 
5788
    {
 
5789
      UP_STATUS (STS_DOINTR);
 
5790
      do_outputintr (dev, intr_flags);
 
5791
      DOWN_STATUS (STS_DOINTR);
 
5792
    }
 
5793
  DOWN_STATUS (STS_INTR);
 
5794
}
 
5795
 
 
5796
void
 
5797
oss_audio_reset (int dev)
 
5798
{
 
5799
  adev_p adev;
 
5800
  if (dev < 0 || dev >= num_audio_engines)
 
5801
    return;
 
5802
  adev = audio_engines[dev];
 
5803
 
 
5804
  audio_reset_adev (adev);
 
5805
 
 
5806
  if (adev->dmask & DMASK_OUT)
 
5807
    reset_dmap (adev->dmap_out);
 
5808
  if (adev->dmask & DMASK_IN)
 
5809
    reset_dmap (adev->dmap_in);
 
5810
}
 
5811
 
 
5812
void
 
5813
oss_audio_start_syncgroup (unsigned int syncgroup)
 
5814
{
 
5815
/*
 
5816
 * This routine is to be called by the /dev/midi driver to start a sync group
 
5817
 * at the right time.
 
5818
 */
 
5819
  oss_native_word flags;
 
5820
 
 
5821
  MUTEX_ENTER_IRQDISABLE (audio_global_mutex, flags);
 
5822
  handle_syncstart (syncgroup & SYNC_DEVICE_MASK, syncgroup);
 
5823
  MUTEX_EXIT_IRQRESTORE (audio_global_mutex, flags);
 
5824
}
 
5825
 
 
5826
#ifdef ALLOW_SELECT
 
5827
/*ARGSUSED*/
 
5828
static int
 
5829
chpoll_output (int dev, struct fileinfo *file, oss_poll_event_t * ev)
 
5830
{
 
5831
  short events = ev->events;
 
5832
  adev_p adev;
 
5833
  dmap_p dmap;
 
5834
  oss_native_word flags;
 
5835
  audio_buf_info bi;
 
5836
  int limit;
 
5837
 
 
5838
#ifdef DO_TIMINGS
 
5839
  oss_timing_printf ("--- audio_chpoll_output(%d, %08x) ---", dev, events);
 
5840
#endif
 
5841
 
 
5842
  if (dev < 0 || dev >= num_audio_engines)
 
5843
    return OSS_ENXIO;
 
5844
  adev = audio_engines[dev];
 
5845
 
 
5846
      dmap = adev->dmap_out;
 
5847
      if (dmap->mapping_flags & DMA_MAP_MAPPED)
 
5848
        {
 
5849
#if 1
 
5850
      /*
 
5851
       * It might actually be better to permit pollling in mmapped
 
5852
       * mode rather than returning an error.
 
5853
       */
 
5854
      if (dmap->interrupt_count > 0)
 
5855
         ev->revents |= (POLLOUT | POLLWRNORM) & events;
 
5856
      return 0;
 
5857
#else
 
5858
          oss_audio_set_error (adev->engine_num, E_PLAY,
 
5859
                               OSSERR (1014,
 
5860
                                       "select/poll called for an OSS device in mmap mode."),
 
5861
                               0);
 
5862
          /*
 
5863
           * Errordesc:
 
5864
           * The select() and poll() system calls are not defined for OSS devices
 
5865
           * when the device is in mmap mode.
 
5866
           */
 
5867
          return OSS_EPERM;
 
5868
#endif
 
5869
        }
 
5870
 
 
5871
      if (dmap->dma_mode == PCM_ENABLE_INPUT)
 
5872
        {
 
5873
          oss_audio_set_error (adev->engine_num, E_PLAY,
 
5874
                               OSSERR (1015,
 
5875
                                       "select/poll called for wrong direction."),
 
5876
                               0);
 
5877
          /*
 
5878
           * Errordesc: The application has opened the device in read-only
 
5879
           * mode but it tried to use select/poll to check if the device is 
 
5880
           * ready for write. This is pointless because that will never
 
5881
           * happen.
 
5882
           */
 
5883
          return 0;
 
5884
        }
 
5885
 
 
5886
      get_ospace (audio_engines[dev], dmap, (ioctl_arg) & bi);
 
5887
      limit = bi.fragsize * bi.fragstotal / 4;
 
5888
      if (dmap->low_water > limit)
 
5889
        dmap->low_water = limit;
 
5890
      MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
5891
      if (bi.bytes < dmap->low_water)
 
5892
        {                       /* No space yet */
 
5893
#ifdef DO_TIMINGS
 
5894
          oss_do_timing ("Output not ready yet");
 
5895
#endif
 
5896
          oss_register_poll (adev->out_wq, &dmap->mutex, &flags, ev);
 
5897
        }
 
5898
      else
 
5899
        {
 
5900
#ifdef DO_TIMINGS
 
5901
          oss_do_timing ("Reporting output ready");
 
5902
#endif
 
5903
          ev->revents |= (POLLOUT | POLLWRNORM) & events;
 
5904
        }
 
5905
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
5906
 
 
5907
  return 0;
 
5908
}
 
5909
 
 
5910
/*ARGSUSED*/
 
5911
static int
 
5912
chpoll_input (int dev, struct fileinfo *file, oss_poll_event_t * ev)
 
5913
{
 
5914
  short events = ev->events;
 
5915
  adev_p adev;
 
5916
  dmap_p dmap;
 
5917
  oss_native_word flags;
 
5918
  audio_buf_info bi;
 
5919
  int limit;
 
5920
 
 
5921
#ifdef DO_TIMINGS
 
5922
  oss_timing_printf ("--- audio_chpoll_input(%d, %08x) ---", dev, events);
 
5923
#endif
 
5924
 
 
5925
  if (dev < 0 || dev >= num_audio_engines)
 
5926
    return OSS_ENXIO;
 
5927
  adev = audio_engines[dev];
 
5928
 
 
5929
  dmap = adev->dmap_in;
 
5930
      if (dmap->mapping_flags & DMA_MAP_MAPPED)
 
5931
        {
 
5932
#if 1
 
5933
      /*
 
5934
       * It might actually be better to permit pollling in mmapped
 
5935
       * mode rather than returning an error.
 
5936
       */
 
5937
      if (dmap->interrupt_count > 0)
 
5938
         ev->revents |= (POLLOUT | POLLWRNORM) & events;
 
5939
      return 0;
 
5940
#else
 
5941
          oss_audio_set_error (adev->engine_num, E_REC,
 
5942
                               OSSERR (1013,
 
5943
                                       "select/poll called for an OSS device in mmap mode."),
 
5944
                               0);
 
5945
          /*
 
5946
           * Errordesc:
 
5947
           * The select() and poll() system calls are not defined for OSS devices
 
5948
           * when the device is in mmap mode.
 
5949
           */
 
5950
          return OSS_EIO;
 
5951
#endif
 
5952
        }
 
5953
 
 
5954
      if (dmap->dma_mode != PCM_ENABLE_INPUT)
 
5955
        {
 
5956
          oss_audio_set_error (adev->engine_num, E_REC,
 
5957
                               OSSERR (1016,
 
5958
                                       "select/poll called for wrong direction."),
 
5959
                               0);
 
5960
          /*
 
5961
           * Errordesc: The application has opened the device in write-only
 
5962
           * mode but it tried to use select/poll to check if the device has any
 
5963
           * data available to read. This is pointless because that will never
 
5964
           * happen.
 
5965
           */
 
5966
          return 0;
 
5967
        }
 
5968
 
 
5969
      if (!(dmap->flags & DMAP_STARTED))
 
5970
        {
 
5971
          oss_audio_set_error (adev->engine_num, E_REC,
 
5972
                               OSSERR (1017,
 
5973
                                       "select/poll called before recording is started."),
 
5974
                               0);
 
5975
          /*
 
5976
           * Errordesc:
 
5977
           * The application should start recording (using SNDCTL_DSP_SETTRIGGER)
 
5978
           * before calling select/poll to wait for recorded data. If recording is
 
5979
           * not active then recorded data will never arrive and the application
 
5980
           * will just sit and wait without doing anything.
 
5981
           */
 
5982
        }
 
5983
 
 
5984
      get_ispace (audio_engines[dev], dmap, (ioctl_arg) & bi);
 
5985
      limit = bi.fragsize * bi.fragstotal / 4;
 
5986
      if (dmap->low_water > limit)
 
5987
        dmap->low_water = limit;
 
5988
      MUTEX_ENTER_IRQDISABLE (dmap->mutex, flags);
 
5989
      if (bi.bytes < dmap->low_water)
 
5990
        {                       /* No space yet */
 
5991
#ifdef DO_TIMINGS
 
5992
          oss_timing_printf ("Input not ready yet (%d/%d)\n", bi.bytes,
 
5993
                   dmap->low_water);
 
5994
#endif
 
5995
          oss_register_poll (adev->in_wq, &dmap->mutex, &flags, ev);
 
5996
        }
 
5997
      else
 
5998
        {
 
5999
#ifdef DO_TIMINGS
 
6000
          oss_do_timing ("Reporting input ready");
 
6001
#endif
 
6002
          ev->revents |= (POLLIN | POLLRDNORM) & events;
 
6003
        }
 
6004
      MUTEX_EXIT_IRQRESTORE (dmap->mutex, flags);
 
6005
 
 
6006
  return 0;
 
6007
}
 
6008
 
 
6009
/*ARGSUSED*/
 
6010
int
 
6011
oss_audio_chpoll (int dev, struct fileinfo *file, oss_poll_event_t * ev)
 
6012
{
 
6013
  short events = ev->events;
 
6014
  adev_p adev;
 
6015
 
 
6016
#ifdef DO_TIMINGS
 
6017
  oss_timing_printf ("--- audio_chpoll(%d, %08x) ---", dev, events);
 
6018
#endif
 
6019
 
 
6020
  if (dev < 0 || dev >= num_audio_engines)
 
6021
    return OSS_ENXIO;
 
6022
  adev = audio_engines[dev];
 
6023
 
 
6024
  if ((events & (POLLOUT | POLLWRNORM)) && (adev->open_mode & OPEN_WRITE))
 
6025
    {
 
6026
            int err;
 
6027
 
 
6028
            if ((err=chpoll_output (dev, file, ev))<0)
 
6029
               return err;
 
6030
    }
 
6031
 
 
6032
  if ((events & (POLLIN | POLLRDNORM)) && (adev->open_mode & OPEN_READ))
 
6033
    {
 
6034
            int err;
 
6035
 
 
6036
            if ((err=chpoll_input (dev, file, ev))<0)
 
6037
               return err;
 
6038
    }
 
6039
 
 
6040
  return 0;
 
6041
}
 
6042
#endif
 
6043
 
 
6044
/*ARGSUSED*/
 
6045
static void
 
6046
dummy_inputintr (int dev, int intr_flags)
 
6047
{
 
6048
  /* Dummy input interrupt handler */
 
6049
}
 
6050
 
 
6051
/*ARGSUSED*/
 
6052
static void
 
6053
dummy_outputintr (int dev, int x)
 
6054
{
 
6055
  /* Dummy output interrupt handler */
 
6056
}
 
6057
 
 
6058
static oss_cdev_drv_t audio_cdev_drv = {
 
6059
#ifdef VDEV_SUPPORT
 
6060
  oss_audio_open_devfile,
 
6061
#else
 
6062
  oss_audio_open_engine,
 
6063
#endif
 
6064
  oss_audio_release,
 
6065
  oss_audio_read,
 
6066
  oss_audio_write,
 
6067
  oss_audio_ioctl,
 
6068
#ifdef ALLOW_SELECT
 
6069
  oss_audio_chpoll
 
6070
#else
 
6071
  NULL
 
6072
#endif
 
6073
};
 
6074
 
 
6075
#ifdef MANAGE_DEV_DSP
 
6076
#ifdef VDEV_SUPPORT
 
6077
static oss_cdev_drv_t vdsp_cdev_drv = {
 
6078
  oss_open_vdsp,
 
6079
  oss_audio_release,
 
6080
  oss_audio_read,
 
6081
  oss_audio_write,
 
6082
  oss_audio_ioctl,
 
6083
#ifdef ALLOW_SELECT
 
6084
  oss_audio_chpoll
 
6085
#else
 
6086
  NULL
 
6087
#endif
 
6088
};
 
6089
#endif
 
6090
#endif
 
6091
 
 
6092
static oss_cdev_drv_t audio_engine_cdev_drv = {
 
6093
  oss_audio_open_engine,
 
6094
  oss_audio_release,
 
6095
  oss_audio_read,
 
6096
  oss_audio_write,
 
6097
  oss_audio_ioctl,
 
6098
#ifdef ALLOW_SELECT
 
6099
  oss_audio_chpoll
 
6100
#else
 
6101
  NULL
 
6102
#endif
 
6103
};
 
6104
 
 
6105
void
 
6106
oss_audio_register_client (oss_audio_startup_func func, void *devc,
 
6107
                           oss_device_t * osdev)
 
6108
{
 
6109
/*
 
6110
 * Register a callback for a driver that wants to be initialized after a new audio device
 
6111
 * is installed.
 
6112
 */
 
6113
 
 
6114
  if (num_audio_startups >= MAX_STARTUPS)
 
6115
    return;
 
6116
 
 
6117
  audio_startups[num_audio_startups].func = func;
 
6118
  audio_startups[num_audio_startups].devc = devc;
 
6119
  audio_startups[num_audio_startups].osdev = osdev;
 
6120
  num_audio_startups++;
 
6121
}
 
6122
 
 
6123
void
 
6124
oss_add_audio_devlist (int list_id, int devfile)
 
6125
{
 
6126
#if 0
 
6127
/*
 
6128
 * Device list support is not in use at this moment
 
6129
 */
 
6130
  oss_devlist_t *list;
 
6131
  int i;
 
6132
 
 
6133
  switch (list_id)
 
6134
    {
 
6135
    case OPEN_READ:
 
6136
      list = &dspinlist;
 
6137
      break;
 
6138
 
 
6139
    case OPEN_WRITE:
 
6140
      list = &dspoutlist;
 
6141
      break;
 
6142
 
 
6143
    case OPEN_READ | OPEN_WRITE:
 
6144
      list = &dspinoutlist;
 
6145
      break;
 
6146
 
 
6147
    default:
 
6148
      cmn_err (CE_CONT, "Bad device list ID %d\n", list_id);
 
6149
      return;
 
6150
    }
 
6151
 
 
6152
  for (i = 0; i < list->ndevs; i++)
 
6153
    if (list->devices[i] == devfile)    /* Already there */
 
6154
      return;
 
6155
 
 
6156
  /*
 
6157
   * Add the device to the list
 
6158
   */
 
6159
  list->devices[list->ndevs++] = devfile;
 
6160
#endif
 
6161
}
 
6162
 
 
6163
#if 0
 
6164
static void
 
6165
add_to_devlists (adev_p adev)
 
6166
{
 
6167
/*
 
6168
 * Add the device to the default input, output and/or input/output lists
 
6169
 * for /dev/dsp.
 
6170
 */
 
6171
 
 
6172
  if (!(adev->flags & ADEV_SPECIAL))
 
6173
    {
 
6174
      if (!(adev->flags & ADEV_NOOUTPUT))
 
6175
        {                       /* Output capable */
 
6176
 
 
6177
          if (adev->flags & ADEV_VIRTUAL)
 
6178
            {
 
6179
              int n = dspoutlist.ndevs++;
 
6180
 
 
6181
              if (adev->flags & ADEV_DEFAULT)
 
6182
                {
 
6183
                  int i;
 
6184
 
 
6185
                  for (i = n; i > 0; i--)
 
6186
                    dspoutlist.devices[i] = dspoutlist.devices[i - 1];
 
6187
                  dspoutlist.devices[0] = adev->audio_devfile;
 
6188
                }
 
6189
              else
 
6190
                dspoutlist.devices[n] = adev->audio_devfile;
 
6191
            }
 
6192
          else
 
6193
            {
 
6194
              /* Put non-virtual devices to a secondary list */
 
6195
              int n = dspoutlist2.ndevs++;
 
6196
              dspoutlist2.devices[n] = adev->audio_devfile;
 
6197
            }
 
6198
 
 
6199
        }
 
6200
 
 
6201
      if (!(adev->flags & (ADEV_NOINPUT)))
 
6202
        {                       /* Input capable */
 
6203
 
 
6204
          int n = dspinlist.ndevs++;
 
6205
 
 
6206
          if (adev->flags & ADEV_DEFAULT)
 
6207
            {
 
6208
              int i;
 
6209
 
 
6210
              for (i = n; i > 0; i--)
 
6211
                dspinlist.devices[i] = dspinlist.devices[i - 1];
 
6212
              dspinlist.devices[0] = adev->audio_devfile;
 
6213
            }
 
6214
          else
 
6215
            dspinlist.devices[n] = adev->audio_devfile;
 
6216
        }
 
6217
 
 
6218
      if (!(adev->flags & (ADEV_NOINPUT | ADEV_NOOUTPUT))
 
6219
          || (adev->flags & ADEV_DUPLEX))
 
6220
        {                       /* Input/output capable */
 
6221
 
 
6222
          int n = dspinoutlist.ndevs++;
 
6223
 
 
6224
          if (adev->flags & ADEV_DEFAULT)
 
6225
            {
 
6226
              int i;
 
6227
 
 
6228
              for (i = n; i > 0; i--)
 
6229
                dspinoutlist.devices[i] = dspinoutlist.devices[i - 1];
 
6230
              dspinoutlist.devices[0] = adev->audio_devfile;
 
6231
            }
 
6232
          else
 
6233
            dspinoutlist.devices[n] = adev->audio_devfile;
 
6234
        }
 
6235
    }
 
6236
}
 
6237
#endif
 
6238
 
 
6239
static int
 
6240
resize_array(oss_device_t *osdev, adev_t ***arr, int *size, int increment)
 
6241
{
 
6242
        adev_t **old=*arr, **new = *arr;
 
6243
        int old_size = *size;
 
6244
        int new_size = *size;
 
6245
                
 
6246
        if (new_size >= HARD_MAX_AUDIO_DEVFILES) /* Too many device files */
 
6247
           return 0;
 
6248
 
 
6249
        new_size += increment;
 
6250
        if (new_size > HARD_MAX_AUDIO_DEVFILES)
 
6251
           new_size = HARD_MAX_AUDIO_DEVFILES;
 
6252
 
 
6253
        if ((new=AUDIO_MALLOC(osdev, new_size * sizeof (adev_t *)))==NULL)
 
6254
           return 0;
 
6255
 
 
6256
        memset(new, 0, new_size * sizeof(adev_t *));
 
6257
        if (old != NULL)
 
6258
           memcpy(new, old, old_size * sizeof(adev_t *));
 
6259
 
 
6260
        *size = new_size;
 
6261
        *arr = new;
 
6262
 
 
6263
        if (old != NULL)
 
6264
           AUDIO_FREE(osdev, old);
 
6265
 
 
6266
        return 1;
 
6267
}
 
6268
 
 
6269
int
 
6270
oss_install_audiodev_with_devname (int vers,
 
6271
                      oss_device_t * osdev,
 
6272
                      oss_device_t * master_osdev,
 
6273
                      char *name,
 
6274
                      const audiodrv_t * driver,
 
6275
                      int driver_size,
 
6276
                      int flags,
 
6277
                      unsigned int format_mask, void *devc, int parent,
 
6278
                      const char * devfile_name)
 
6279
{
 
6280
  audiodrv_t *d;
 
6281
  adev_t *op;
 
6282
  int i, num = -1, hidden_device = 0;
 
6283
  int update_devlists = 0;
 
6284
  int reinsterted_device = 0;
 
6285
  int chdev_flags = 0;
 
6286
  int devfile_num = 0;
 
6287
 
 
6288
  if (devc == NULL)
 
6289
     {
 
6290
             cmn_err(CE_WARN, "devc==NULL for %s. Cannot install audio device\n", name);
 
6291
             return OSS_EINVAL;
 
6292
     }
 
6293
 
 
6294
  if (name == NULL)
 
6295
    cmn_err (CE_CONT, "Name is really NULL\n");
 
6296
  if (master_osdev == NULL)
 
6297
    master_osdev = osdev;
 
6298
 
 
6299
#ifdef VDEV_SUPPORT
 
6300
  if (flags & (ADEV_SHADOW | ADEV_HIDDEN))
 
6301
    hidden_device = 1;
 
6302
#else
 
6303
  flags &= ~ADEV_HIDDEN;
 
6304
  hidden_device = 0;
 
6305
#endif
 
6306
 
 
6307
  if (audio_engines == NULL)
 
6308
    {
 
6309
      audio_engines = AUDIO_MALLOC (NULL, sizeof (adev_t *) * MAX_AUDIO_ENGINES);
 
6310
      memset (audio_engines, 0, sizeof (adev_t *) * MAX_AUDIO_ENGINES);
 
6311
    }
 
6312
 
 
6313
  if (audio_devfiles == NULL)
 
6314
    {
 
6315
      audio_devfiles = AUDIO_MALLOC (NULL, sizeof (adev_t *) * MAX_AUDIO_DEVFILES);
 
6316
      memset (audio_devfiles, 0, sizeof (adev_t *) * MAX_AUDIO_DEVFILES);
 
6317
    }
 
6318
 
 
6319
  if (vers != OSS_AUDIO_DRIVER_VERSION)
 
6320
    {
 
6321
      cmn_err (CE_WARN, "Incompatible audio driver for %s\n", name);
 
6322
      return OSS_EIO;
 
6323
    }
 
6324
 
 
6325
  if (driver_size > sizeof (audiodrv_t))
 
6326
    driver_size = sizeof (audiodrv_t);
 
6327
/*
 
6328
 * Try to figure out if this device has earlier been installed. Sometimes it may happen that
 
6329
 * the low level driver gets unloaded while the osscore module still
 
6330
 * remains loaded. Try to re-use the same audio device number if possible.
 
6331
 */
 
6332
 
 
6333
  num = -1;
 
6334
 
 
6335
  for (i = 0; i < num_audio_engines; i++)
 
6336
    {
 
6337
 
 
6338
      if ((audio_engines[i]->flags & (ADEV_SHADOW|ADEV_HIDDEN)) !=
 
6339
                      (flags & (ADEV_SHADOW|ADEV_HIDDEN))) /* Different visibility */
 
6340
         continue;
 
6341
 
 
6342
      if (audio_engines[i]->unloaded
 
6343
          && audio_engines[i]->os_id == oss_get_osid (osdev))
 
6344
        {
 
6345
          /* This audio device was previously connected to the same physical device */
 
6346
 
 
6347
          num = i;
 
6348
          reinsterted_device = 1;
 
6349
          DDB (cmn_err
 
6350
               (CE_NOTE, "Audio device %d got re-installed again.\n", i));
 
6351
          break;
 
6352
        }
 
6353
    }
 
6354
 
 
6355
  if (num == -1)
 
6356
    {
 
6357
 
 
6358
      if (num_audio_engines >= MAX_AUDIO_ENGINES)
 
6359
        {
 
6360
                if (!resize_array(osdev, &audio_engines, &oss_max_audio_engines, AUDIO_ENGINE_INCREMENT))
 
6361
                   {
 
6362
                        cmn_err (CE_CONT, "Cannot grow audio_engines[]\n");
 
6363
                        return OSS_EIO;
 
6364
                   }
 
6365
        }
 
6366
 
 
6367
      d = AUDIO_MALLOC (osdev, sizeof (audiodrv_t));
 
6368
      op = AUDIO_MALLOC (osdev, sizeof (adev_t));
 
6369
      memset ((char *) op, 0, sizeof (adev_t));
 
6370
      if (driver_size < sizeof (audiodrv_t))
 
6371
        memset ((char *) d, 0, sizeof (audiodrv_t));
 
6372
      memcpy ((char *) d, (char *) driver, driver_size);
 
6373
      num = num_audio_engines;
 
6374
      audio_engines[num] = op;
 
6375
      num_audio_engines++;
 
6376
 
 
6377
      update_devlists = 1;
 
6378
 
 
6379
      sprintf (op->handle, "%s-au%02d", osdev->handle,
 
6380
               osdev->num_audio_engines + 1);
 
6381
      op->port_number = osdev->num_audio_engines;
 
6382
    }
 
6383
  else
 
6384
    {
 
6385
      op = audio_engines[num];
 
6386
      d = audio_engines[num]->d;
 
6387
      if (driver_size < sizeof (audiodrv_t))
 
6388
        memset ((char *) d, 0, sizeof (audiodrv_t));
 
6389
      memcpy ((char *) d, (char *) driver, driver_size);
 
6390
      update_devlists = 0;
 
6391
    }
 
6392
 
 
6393
  if (d == NULL || op == NULL)
 
6394
    {
 
6395
      cmn_err (CE_WARN, "Can't allocate driver for %s (adev=%p, d=%p)\n",
 
6396
               name, op, d);
 
6397
      return OSS_ENOSPC;
 
6398
    }
 
6399
 
 
6400
  if (d->adrv_get_input_pointer == NULL)
 
6401
    d->adrv_get_input_pointer = d->adrv_get_buffer_pointer;
 
6402
  if (d->adrv_get_output_pointer == NULL)
 
6403
    d->adrv_get_output_pointer = d->adrv_get_buffer_pointer;
 
6404
 
 
6405
  op->d = d;
 
6406
  op->os_id = oss_get_osid (osdev);
 
6407
  op->enabled = 0;
 
6408
  op->outputintr = dummy_outputintr;
 
6409
  op->inputintr = dummy_inputintr;
 
6410
  op->vmix_mixer = NULL;
 
6411
 
 
6412
  strncpy (op->name, name, sizeof (op->name));
 
6413
  op->name[sizeof (op->name) - 1] = 0;
 
6414
  op->caps = 0;
 
6415
 
 
6416
  op->flags = flags;
 
6417
  op->latency = -1;             /* Unknown */
 
6418
 
 
6419
  op->oformat_mask = format_mask;
 
6420
  op->iformat_mask = format_mask;
 
6421
  op->mixer_dev = -1;
 
6422
  op->min_channels = 1;
 
6423
  op->max_channels = 2;
 
6424
  op->min_rate = 8000;
 
6425
  op->max_rate = 44100;
 
6426
  op->devc = devc;
 
6427
  op->parent_dev = parent + 1;
 
6428
  op->dmap_in = NULL;
 
6429
  op->dmap_out = NULL;
 
6430
  memset (op->cmd, 0, sizeof (op->cmd));
 
6431
  op->pid = -1;
 
6432
  op->osdev = osdev;
 
6433
  op->master_osdev = master_osdev;
 
6434
  op->card_number = osdev->cardnum;
 
6435
  op->engine_num = op->rate_source = num;
 
6436
  op->real_dev = num;
 
6437
  op->redirect_in = -1;
 
6438
  op->redirect_out = -1;
 
6439
  op->dmabuf_alloc_flags = 0;
 
6440
  op->dmabuf_maxaddr = MEMLIMIT_32BITS;
 
6441
 
 
6442
  audio_engines[num] = op;
 
6443
  op->next_out = NULL;
 
6444
  op->next_in = NULL;
 
6445
 
 
6446
  op->song_name[0] = 0;
 
6447
  op->label[0] = 0;
 
6448
  op->nrates=0;
 
6449
 
 
6450
  if ((flags & ADEV_SHADOW) && num > 0)
 
6451
    {
 
6452
      adev_p prev = audio_engines[num - 1];     /* Previous device */
 
6453
 
 
6454
      prev->next_out = op;
 
6455
      prev->next_in = op;
 
6456
    }
 
6457
 
 
6458
  if (audio_init_device (num) < 0)
 
6459
    return OSS_ENOMEM;
 
6460
 
 
6461
/*
 
6462
 * Create the device node.
 
6463
 */
 
6464
#ifndef VDEV_SUPPORT
 
6465
  flat_device_model = 1;
 
6466
  hidden_device = 0;
 
6467
#endif
 
6468
 
 
6469
  if (reinsterted_device)
 
6470
    {
 
6471
      /*
 
6472
       * A hotpluggable device has been reinserted in the system.
 
6473
       * Update the internal tables and re-create the device file entry.
 
6474
       * However don't create new audio engine and device file numbers.
 
6475
       */
 
6476
      devfile_num = op->audio_devfile;
 
6477
      chdev_flags |= CHDEV_REPLUG;
 
6478
    }
 
6479
  else
 
6480
    {
 
6481
      if (!hidden_device)
 
6482
        {
 
6483
          if (num_audio_devfiles >= MAX_AUDIO_DEVFILES)
 
6484
             {
 
6485
                if (!resize_array(osdev, &audio_devfiles, &oss_max_audio_devfiles, AUDIO_DEVFILE_INCREMENT))
 
6486
                   {
 
6487
                        cmn_err (CE_CONT, "Cannot grow audio_devfiles[]\n");
 
6488
                        return num;
 
6489
                   }
 
6490
             }
 
6491
 
 
6492
             audio_devfiles[num_audio_devfiles] = op;
 
6493
             devfile_num = num_audio_devfiles++;
 
6494
        }
 
6495
    }
 
6496
 
 
6497
  if (flat_device_model || !hidden_device)
 
6498
    {
 
6499
#ifdef NEW_DEVICE_NAMING
 
6500
      oss_devnode_t name;
 
6501
      char tmpl[32];
 
6502
 
 
6503
      if (*devfile_name != 0)
 
6504
        {
 
6505
          /*
 
6506
           * A name was suggested by the low level driver
 
6507
           */
 
6508
          strcpy (tmpl, devfile_name);
 
6509
        }
 
6510
      else if (flags & ADEV_NOOUTPUT)
 
6511
        sprintf (tmpl, "pcmin%d", osdev->num_audiorec++);
 
6512
      else
 
6513
        sprintf (tmpl, "pcm%d", osdev->num_audioduplex++);
 
6514
 
 
6515
# ifdef USE_DEVICE_SUBDIRS
 
6516
      sprintf (name, "oss/%s/%s", osdev->nick, tmpl);
 
6517
# else
 
6518
      sprintf (name, "%s_%s", osdev->nick, tmpl);
 
6519
# endif
 
6520
#else
 
6521
      sprintf (name, "dsp%d", num);
 
6522
#endif
 
6523
 
 
6524
      op->real_dev = devfile_num;
 
6525
      op->audio_devfile = devfile_num;
 
6526
      audio_devfiles[devfile_num] = op;
 
6527
      sprintf (op->devnode, "/dev/%s", name);
 
6528
      oss_install_chrdev (master_osdev, name, OSS_DEV_DSP, devfile_num,
 
6529
                          &audio_cdev_drv, chdev_flags);
 
6530
      osdev->num_audio_engines++;
 
6531
 
 
6532
      op->enabled = 1;
 
6533
      op->unloaded = 0;
 
6534
 
 
6535
    }
 
6536
  else
 
6537
    {
 
6538
      op->real_dev = -1;
 
6539
      if (devfile_num > 0 && (flags & ADEV_SHADOW))
 
6540
        {
 
6541
          /* Use the device node of the parent device file */
 
6542
          if (audio_devfiles[devfile_num - 1] != NULL)
 
6543
            strcpy (op->devnode, audio_devfiles[devfile_num - 1]->devnode);
 
6544
          else
 
6545
            strcpy (op->devnode, "Unknown");
 
6546
          audio_devfiles[devfile_num] = op;
 
6547
        }
 
6548
      else
 
6549
        {
 
6550
          strcpy (op->devnode, "HiddenAudioDevice");
 
6551
        }
 
6552
      op->enabled = 1;
 
6553
      op->unloaded = 0;
 
6554
    }
 
6555
 
 
6556
//#ifdef VDEV_SUPPORT
 
6557
  oss_install_chrdev (osdev, NULL, OSS_DEV_DSP_ENGINE, num,
 
6558
                      &audio_engine_cdev_drv, chdev_flags);
 
6559
//#endif
 
6560
 
 
6561
#if 0
 
6562
  if (!reinsterted_device && update_devlists && !hidden_device)
 
6563
    add_to_devlists (op);
 
6564
#endif
 
6565
 
 
6566
  {
 
6567
    int i;
 
6568
    for (i = 0; i < num_audio_engines; i++)
 
6569
      if (audio_engines[i] == NULL)
 
6570
        cmn_err (CE_WARN, "Audio engines %d==NULL\n", i);
 
6571
    for (i = 0; i < num_audio_devfiles; i++)
 
6572
      if (audio_devfiles[i] == NULL)
 
6573
        cmn_err (CE_WARN, "Audio devfiles %d==NULL\n", i);
 
6574
  }
 
6575
 
 
6576
  return num;
 
6577
}
 
6578
 
 
6579
int
 
6580
oss_install_audiodev (int vers,
 
6581
                      oss_device_t * osdev,
 
6582
                      oss_device_t * master_osdev,
 
6583
                      char *name,
 
6584
                      const audiodrv_t * driver,
 
6585
                      int driver_size,
 
6586
                      unsigned long long flags,
 
6587
                      unsigned int format_mask, void *devc, int parent)
 
6588
{
 
6589
 return oss_install_audiodev_with_devname (vers,
 
6590
                      osdev,
 
6591
                      master_osdev,
 
6592
                      name,
 
6593
                      driver,
 
6594
                      driver_size,
 
6595
                      flags,
 
6596
                      format_mask, devc, parent,
 
6597
                      ""); /* Use default device file naming */
 
6598
}
 
6599
 
 
6600
void
 
6601
oss_audio_delayed_attach (void)
 
6602
{
 
6603
  int i;
 
6604
 
 
6605
  /*
 
6606
   * Serve possible other drivers waiting for new friends.
 
6607
   */
 
6608
  for (i = 0; i < num_audio_startups; i++)
 
6609
    {
 
6610
      if (audio_startups[i].osdev != NULL
 
6611
          && audio_startups[i].osdev->available)
 
6612
        {
 
6613
          if (audio_startups[i].func (audio_startups[i].devc))
 
6614
            audio_startups[i].osdev = NULL;     /* Inactivate it */
 
6615
        }
 
6616
    }
 
6617
}
 
6618
 
 
6619
/*ARGSUSED*/
 
6620
void
 
6621
install_vdsp (oss_device_t * osdev)
 
6622
{
 
6623
#ifdef MANAGE_DEV_DSP
 
6624
/*
 
6625
 * Install the driver for /dev/dsp (the multiplexer device)
 
6626
 *
 
6627
 * NOTE! Not used at this moment because /dev/dsp assignment is managed in user
 
6628
 *       space (by ossdevlinks).
 
6629
 */
 
6630
#ifdef VDEV_SUPPORT
 
6631
  oss_install_chrdev (osdev, "dsp", OSS_DEV_VDSP, 0, &vdsp_cdev_drv,
 
6632
                      CHDEV_VIRTUAL);
 
6633
  oss_install_chrdev (osdev, "dsp_in", OSS_DEV_VDSP, 1, &vdsp_cdev_drv,
 
6634
                      CHDEV_VIRTUAL);
 
6635
  oss_install_chrdev (osdev, "dsp_out", OSS_DEV_VDSP, 2, &vdsp_cdev_drv,
 
6636
                      CHDEV_VIRTUAL);
 
6637
#endif
 
6638
#endif
 
6639
}