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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [sound/] [soundcard.c] - Blame information for rev 1777

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

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 * linux/kernel/chr_drv/sound/soundcard.c
3
 *
4
 * Soundcard driver for Linux
5
 */
6
/*
7
 * Copyright (C) by Hannu Savolainen 1993-1996
8
 *
9
 * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
10
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
11
 * for more info.
12
 */
13
#include <linux/config.h>
14
 
15
 
16
#include "sound_config.h"
17
 
18
#include <linux/major.h>
19
 
20
 
21
int            *sound_global_osp = NULL;
22
static int      chrdev_registered = 0;
23
static int      sound_major = SOUND_MAJOR;
24
 
25
static int      is_unloading = 0;
26
 
27
/*
28
 * Table for permanently allocated memory (used when unloading the module)
29
 */
30
caddr_t         sound_mem_blocks[1024];
31
int             sound_nblocks = 0;
32
 
33
static int      soundcard_configured = 0;
34
 
35
static struct fileinfo files[SND_NDEVS];
36
 
37
static char     dma_alloc_map[8] =
38
{0};
39
 
40
#define DMA_MAP_UNAVAIL         0
41
#define DMA_MAP_FREE            1
42
#define DMA_MAP_BUSY            2
43
 
44
 
45
int
46
snd_ioctl_return (int *addr, int value)
47
{
48
  if (value < 0)
49
    return value;
50
 
51
  put_user (value, addr);
52
  return 0;
53
}
54
 
55
static int
56
sound_read (inode_handle * inode, file_handle * file, char *buf, int count)
57
{
58
  int             dev;
59
 
60
  dev = MINOR (inode_get_rdev (inode));
61
 
62
  files[dev].flags = file_get_flags (file);
63
 
64
  return sound_read_sw (dev, &files[dev], buf, count);
65
}
66
 
67
static int
68
sound_write (inode_handle * inode, file_handle * file, const char *buf, int count)
69
{
70
  int             dev;
71
 
72
  dev = MINOR (inode_get_rdev (inode));
73
 
74
  files[dev].flags = file_get_flags (file);
75
 
76
  return sound_write_sw (dev, &files[dev], buf, count);
77
}
78
 
79
static int
80
sound_lseek (inode_handle * inode, file_handle * file, off_t offset, int orig)
81
{
82
  return -(EPERM);
83
}
84
 
85
static int
86
sound_open (inode_handle * inode, file_handle * file)
87
{
88
  int             dev, retval;
89
  struct fileinfo tmp_file;
90
 
91
  if (is_unloading)
92
    {
93
      printk ("Sound: Driver partially removed. Can't open device\n");
94
      return -(EBUSY);
95
    }
96
 
97
  dev = MINOR (inode_get_rdev (inode));
98
 
99
  if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
100
    {
101
      printk ("Sound Card Error: The soundcard system has not been configured\n");
102
      return -(ENXIO);
103
    }
104
 
105
  tmp_file.mode = 0;
106
  tmp_file.flags = file_get_flags (file);
107
 
108
  if ((tmp_file.flags & O_ACCMODE) == O_RDWR)
109
    tmp_file.mode = OPEN_READWRITE;
110
  if ((tmp_file.flags & O_ACCMODE) == O_RDONLY)
111
    tmp_file.mode = OPEN_READ;
112
  if ((tmp_file.flags & O_ACCMODE) == O_WRONLY)
113
    tmp_file.mode = OPEN_WRITE;
114
 
115
  if ((retval = sound_open_sw (dev, &tmp_file)) < 0)
116
    return retval;
117
 
118
#ifdef MODULE
119
  MOD_INC_USE_COUNT;
120
#endif
121
 
122
  memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file));
123
  return retval;
124
}
125
 
126
static void
127
sound_release (inode_handle * inode, file_handle * file)
128
{
129
  int             dev;
130
 
131
  dev = MINOR (inode_get_rdev (inode));
132
 
133
  files[dev].flags = file_get_flags (file);
134
 
135
  sound_release_sw (dev, &files[dev]);
136
#ifdef MODULE
137
  MOD_DEC_USE_COUNT;
138
#endif
139
}
140
 
141
static int
142
sound_ioctl (inode_handle * inode, file_handle * file,
143
             unsigned int cmd, unsigned long arg)
144
{
145
  int             dev, err;
146
 
147
  dev = MINOR (inode_get_rdev (inode));
148
 
149
  files[dev].flags = file_get_flags (file);
150
 
151
  if (_IOC_DIR (cmd) != _IOC_NONE)
152
    {
153
      /*
154
         * Have to validate the address given by the process.
155
       */
156
      int             len;
157
 
158
      len = _IOC_SIZE (cmd);
159
 
160
      if (_IOC_DIR (cmd) & _IOC_WRITE)
161
        {
162
          if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0)
163
            return err;
164
        }
165
 
166
      if (_IOC_DIR (cmd) & _IOC_READ)
167
        {
168
          if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0)
169
            return err;
170
        }
171
 
172
    }
173
 
174
  err = sound_ioctl_sw (dev, &files[dev], cmd, (caddr_t) arg);
175
 
176
  return err;
177
}
178
 
179
static int
180
sound_select (inode_handle * inode, file_handle * file, int sel_type, select_table_handle * wait)
181
{
182
  int             dev;
183
 
184
  dev = MINOR (inode_get_rdev (inode));
185
 
186
  files[dev].flags = file_get_flags (file);
187
 
188
  DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
189
 
190
  switch (dev & 0x0f)
191
    {
192
#ifdef CONFIG_SEQUENCER
193
    case SND_DEV_SEQ:
194
    case SND_DEV_SEQ2:
195
      return sequencer_select (dev, &files[dev], sel_type, wait);
196
      break;
197
#endif
198
 
199
#ifdef CONFIG_MIDI
200
    case SND_DEV_MIDIN:
201
      return MIDIbuf_select (dev, &files[dev], sel_type, wait);
202
      break;
203
#endif
204
 
205
#ifdef CONFIG_AUDIO
206
    case SND_DEV_DSP:
207
    case SND_DEV_DSP16:
208
    case SND_DEV_AUDIO:
209
      return audio_select (dev, &files[dev], sel_type, wait);
210
      break;
211
#endif
212
 
213
    default:
214
      return 0;
215
    }
216
 
217
  return 0;
218
}
219
 
220
static int
221
sound_mmap (inode_handle * inode, file_handle * file, vm_area_handle * vma)
222
{
223
  int             dev, dev_class;
224
  unsigned long   size;
225
  struct dma_buffparms *dmap = NULL;
226
 
227
  dev = MINOR (inode_get_rdev (inode));
228
 
229
  files[dev].flags = file_get_flags (file);
230
 
231
  dev_class = dev & 0x0f;
232
  dev >>= 4;
233
 
234
  if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO)
235
    {
236
      printk ("Sound: mmap() not supported for other than audio devices\n");
237
      return -EINVAL;
238
    }
239
 
240
  if ((vma_get_flags (vma) & (VM_READ | VM_WRITE)) == (VM_READ | VM_WRITE))
241
    {
242
      printk ("Sound: Cannot do read/write mmap()\n");
243
      return -EINVAL;
244
    }
245
 
246
  if (vma_get_flags (vma) & VM_READ)
247
    {
248
      dmap = audio_devs[dev]->dmap_in;
249
    }
250
  else if (vma_get_flags (vma) & VM_WRITE)
251
    {
252
      dmap = audio_devs[dev]->dmap_out;
253
    }
254
  else
255
    {
256
      printk ("Sound: Undefined mmap() access\n");
257
      return -EINVAL;
258
    }
259
 
260
  if (dmap == NULL)
261
    {
262
      printk ("Sound: mmap() error. dmap == NULL\n");
263
      return -EIO;
264
    }
265
 
266
  if (dmap->raw_buf == NULL)
267
    {
268
      printk ("Sound: mmap() called when raw_buf == NULL\n");
269
      return -EIO;
270
    }
271
 
272
  if (dmap->mapping_flags)
273
    {
274
      printk ("Sound: mmap() called twice for the same DMA buffer\n");
275
      return -EIO;
276
    }
277
 
278
  if (vma_get_offset (vma) != 0)
279
    {
280
      printk ("Sound: mmap() offset must be 0.\n");
281
      return -EINVAL;
282
    }
283
 
284
  size = vma_get_end (vma) - vma_get_start (vma);
285
 
286
  if (size != dmap->bytes_in_use)
287
    {
288
      printk ("Sound: mmap() size = %ld. Should be %d\n",
289
              size, dmap->bytes_in_use);
290
    }
291
 
292
  if (remap_page_range (vma_get_start (vma), (unsigned long)dmap->raw_buf,
293
                        vma_get_end (vma) - vma_get_start (vma),
294
                        vma_get_page_prot (vma)))
295
    return -EAGAIN;
296
 
297
  vma_set_inode (vma, inode);
298
  inode_inc_count (inode);
299
 
300
  dmap->mapping_flags |= DMA_MAP_MAPPED;
301
 
302
  memset (dmap->raw_buf,
303
          dmap->neutral_byte,
304
          dmap->bytes_in_use);
305
  return 0;
306
}
307
 
308
static struct file_operation_handle sound_fops =
309
{
310
  sound_lseek,
311
  sound_read,
312
  sound_write,
313
  NULL,                         /* sound_readdir */
314
  sound_select,
315
  sound_ioctl,
316
  sound_mmap,
317
  sound_open,
318
  sound_release
319
};
320
 
321
void
322
soundcard_init (void)
323
{
324
#ifndef MODULE
325
  module_register_chrdev (sound_major, "sound", &sound_fops);
326
  chrdev_registered = 1;
327
#endif
328
 
329
  soundcard_configured = 1;
330
 
331
  sndtable_init ();             /* Initialize call tables and detect cards */
332
 
333
 
334
 
335
#ifdef CONFIG_LOWLEVEL_SOUND
336
  {
337
    extern void     sound_init_lowlevel_drivers (void);
338
 
339
    sound_init_lowlevel_drivers ();
340
  }
341
#endif
342
 
343
  if (sndtable_get_cardcount () == 0)
344
    return;                     /* No cards detected */
345
 
346
#ifdef CONFIG_AUDIO
347
  if (num_audiodevs)            /* Audio devices present */
348
    {
349
      DMAbuf_init ();
350
      audio_init ();
351
    }
352
#endif
353
 
354
#ifdef CONFIG_MIDI
355
  if (num_midis)
356
    MIDIbuf_init ();
357
#endif
358
 
359
#ifdef CONFIG_SEQUENCER
360
  if (num_midis + num_synths)
361
    sequencer_init ();
362
#endif
363
 
364
}
365
 
366
static unsigned int irqs = 0;
367
 
368
#ifdef MODULE
369
static void
370
free_all_irqs (void)
371
{
372
  int             i;
373
 
374
  for (i = 0; i < 31; i++)
375
    if (irqs & (1ul << i))
376
      {
377
        printk ("Sound warning: IRQ%d was left allocated - fixed.\n", i);
378
        snd_release_irq (i);
379
      }
380
  irqs = 0;
381
}
382
 
383
char            kernel_version[] = UTS_RELEASE;
384
 
385
#endif
386
 
387
static int      debugmem = 0;    /* switched off by default */
388
 
389
static int      sound[20] =
390
{0};
391
 
392
int
393
init_module (void)
394
{
395
  int             err;
396
  int             ints[21];
397
  int             i;
398
 
399
  if (connect_wrapper (WRAPPER_VERSION) < 0)
400
    {
401
      printk ("Sound: Incompatible kernel (wrapper) version\n");
402
      return -EINVAL;
403
    }
404
 
405
  /*
406
     * "sound=" command line handling by Harald Milz.
407
   */
408
  i = 0;
409
  while (i < 20 && sound[i])
410
    ints[i + 1] = sound[i++];
411
  ints[0] = i;
412
 
413
  if (i)
414
    sound_setup ("sound=", ints);
415
 
416
  err = module_register_chrdev (sound_major, "sound", &sound_fops);
417
  if (err)
418
    {
419
      printk ("sound: driver already loaded/included in kernel\n");
420
      return err;
421
    }
422
 
423
  chrdev_registered = 1;
424
  soundcard_init ();
425
 
426
  if (sound_nblocks >= 1024)
427
    printk ("Sound warning: Deallocation table was too small.\n");
428
 
429
  return 0;
430
}
431
 
432
#ifdef MODULE
433
 
434
 
435
void
436
cleanup_module (void)
437
{
438
  int             i;
439
 
440
  if (MOD_IN_USE)
441
    {
442
      return;
443
    }
444
 
445
  if (chrdev_registered)
446
    module_unregister_chrdev (sound_major, "sound");
447
 
448
#ifdef CONFIG_SEQUENCER
449
  sound_stop_timer ();
450
#endif
451
 
452
#ifdef CONFIG_LOWLEVEL_SOUND
453
  {
454
    extern void     sound_unload_lowlevel_drivers (void);
455
 
456
    sound_unload_lowlevel_drivers ();
457
  }
458
#endif
459
  sound_unload_drivers ();
460
 
461
  for (i = 0; i < sound_nblocks; i++)
462
    vfree (sound_mem_blocks[i]);
463
 
464
  free_all_irqs ();             /* If something was left allocated by accident */
465
 
466
  for (i = 0; i < 8; i++)
467
    if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
468
      {
469
        printk ("Sound: Hmm, DMA%d was left allocated - fixed\n", i);
470
        sound_free_dma (i);
471
      }
472
 
473
 
474
}
475
#endif
476
 
477
void
478
tenmicrosec (int *osp)
479
{
480
  int             i;
481
 
482
  for (i = 0; i < 16; i++)
483
    inb (0x80);
484
}
485
 
486
int
487
snd_set_irq_handler (int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp)
488
{
489
  int             retcode;
490
  unsigned long   flags;
491
 
492
  save_flags (flags);
493
  cli ();
494
 
495
  retcode = request_irq (interrupt_level, iproc, 0 /* SA_INTERRUPT */ , name, NULL);
496
  if (retcode < 0)
497
    {
498
      printk ("Sound: IRQ%d already in use\n", interrupt_level);
499
    }
500
  else
501
    irqs |= (1ul << interrupt_level);
502
 
503
  restore_flags (flags);
504
  return retcode;
505
}
506
 
507
void
508
snd_release_irq (int vect)
509
{
510
  if (!(irqs & (1ul << vect)))
511
    return;
512
 
513
  irqs &= ~(1ul << vect);
514
  free_irq (vect, NULL);
515
}
516
 
517
int
518
sound_alloc_dma (int chn, char *deviceID)
519
{
520
  int             err;
521
 
522
  if ((err = request_dma (chn, deviceID)) != 0)
523
    return err;
524
 
525
  dma_alloc_map[chn] = DMA_MAP_FREE;
526
 
527
  return 0;
528
}
529
 
530
int
531
sound_open_dma (int chn, char *deviceID)
532
{
533
  unsigned long   flags;
534
 
535
  if (chn < 0 || chn > 7 || chn == 4)
536
    {
537
      printk ("sound_open_dma: Invalid DMA channel %d\n", chn);
538
      return 1;
539
    }
540
 
541
  save_flags (flags);
542
  cli ();
543
 
544
  if (dma_alloc_map[chn] != DMA_MAP_FREE)
545
    {
546
      printk ("sound_open_dma: DMA channel %d busy or not allocated\n", chn);
547
      restore_flags (flags);
548
      return 1;
549
    }
550
 
551
  dma_alloc_map[chn] = DMA_MAP_BUSY;
552
  restore_flags (flags);
553
  return 0;
554
}
555
 
556
void
557
sound_free_dma (int chn)
558
{
559
  if (dma_alloc_map[chn] != DMA_MAP_FREE)
560
    {
561
      /* printk ("sound_free_dma: Bad access to DMA channel %d\n", chn); */
562
      return;
563
    }
564
  free_dma (chn);
565
  dma_alloc_map[chn] = DMA_MAP_UNAVAIL;
566
}
567
 
568
void
569
sound_close_dma (int chn)
570
{
571
  unsigned long   flags;
572
 
573
  save_flags (flags);
574
  cli ();
575
 
576
  if (dma_alloc_map[chn] != DMA_MAP_BUSY)
577
    {
578
      printk ("sound_close_dma: Bad access to DMA channel %d\n", chn);
579
      restore_flags (flags);
580
      return;
581
    }
582
  dma_alloc_map[chn] = DMA_MAP_FREE;
583
  restore_flags (flags);
584
}
585
 
586
#ifdef CONFIG_SEQUENCER
587
 
588
 
589
static struct timer_list seq_timer =
590
{NULL, NULL, 0, 0, sequencer_timer};
591
 
592
void
593
request_sound_timer (int count)
594
{
595
  extern unsigned long seq_time;
596
 
597
  if (count < 0)
598
    count = jiffies + (-count);
599
  else
600
    count += seq_time;
601
 
602
  ;
603
 
604
  {
605
    seq_timer.expires = ((count - jiffies)) + jiffies;
606
    add_timer (&seq_timer);
607
  };
608
}
609
 
610
void
611
sound_stop_timer (void)
612
{
613
  del_timer (&seq_timer);;
614
}
615
#endif
616
 
617
#ifdef CONFIG_AUDIO
618
 
619
#ifdef KMALLOC_DMA_BROKEN
620
fatal_error__This_version_is_not_compatible_with_this_kernel;
621
#endif
622
 
623
static int      dma_buffsize = DSP_BUFFSIZE;
624
 
625
int
626
sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan)
627
{
628
  char           *start_addr, *end_addr;
629
  int             i, dma_pagesize;
630
 
631
  dmap->mapping_flags &= ~DMA_MAP_MAPPED;
632
 
633
  if (dmap->raw_buf != NULL)
634
    return 0;                    /* Already done */
635
 
636
  if (dma_buffsize < 4096)
637
    dma_buffsize = 4096;
638
 
639
  if (chan < 4)
640
    dma_pagesize = 64 * 1024;
641
  else
642
    dma_pagesize = 128 * 1024;
643
 
644
  dmap->raw_buf = NULL;
645
 
646
  if (debugmem)
647
    printk ("sound: buffsize[%d] = %lu\n", dev, audio_devs[dev]->buffsize);
648
 
649
  audio_devs[dev]->buffsize = dma_buffsize;
650
 
651
  if (audio_devs[dev]->buffsize > dma_pagesize)
652
    audio_devs[dev]->buffsize = dma_pagesize;
653
 
654
  start_addr = NULL;
655
 
656
/*
657
 * Now loop until we get a free buffer. Try to get smaller buffer if
658
 * it fails.
659
 */
660
 
661
  while (start_addr == NULL && audio_devs[dev]->buffsize > PAGE_SIZE)
662
    {
663
      int             sz, size;
664
 
665
      for (sz = 0, size = PAGE_SIZE;
666
           size < audio_devs[dev]->buffsize;
667
           sz++, size <<= 1);
668
 
669
      audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz);
670
 
671
      if ((start_addr = (char *) __get_dma_pages (GFP_ATOMIC, sz)) == NULL)
672
        audio_devs[dev]->buffsize /= 2;
673
    }
674
 
675
  if (start_addr == NULL)
676
    {
677
      printk ("Sound error: Couldn't allocate DMA buffer\n");
678
      return -(ENOMEM);
679
    }
680
  else
681
    {
682
      /* make some checks */
683
      end_addr = start_addr + audio_devs[dev]->buffsize - 1;
684
 
685
      if (debugmem)
686
        printk ("sound: start 0x%lx, end 0x%lx\n",
687
                (long) start_addr, (long) end_addr);
688
 
689
      /* now check if it fits into the same dma-pagesize */
690
 
691
      if (((long) start_addr & ~(dma_pagesize - 1))
692
          != ((long) end_addr & ~(dma_pagesize - 1))
693
          || end_addr >= (char *) (MAX_DMA_ADDRESS))
694
        {
695
          printk (
696
                   "sound: Got invalid address 0x%lx for %ldb DMA-buffer\n",
697
                   (long) start_addr,
698
                   audio_devs[dev]->buffsize);
699
          return -(EFAULT);
700
        }
701
    }
702
  dmap->raw_buf = start_addr;
703
  dmap->raw_buf_phys = virt_to_bus (start_addr);
704
 
705
  for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
706
    {
707
      mem_map_reserve (i);
708
    }
709
 
710
  return 0;
711
}
712
 
713
void
714
sound_free_dmap (int dev, struct dma_buffparms *dmap)
715
{
716
  int             sz, size, i;
717
  unsigned long   start_addr, end_addr;
718
 
719
  if (dmap->raw_buf == NULL)
720
    return;
721
 
722
  if (dmap->mapping_flags & DMA_MAP_MAPPED)
723
    return;                     /* Don't free mmapped buffer. Will use it next time */
724
 
725
  for (sz = 0, size = PAGE_SIZE;
726
       size < audio_devs[dev]->buffsize;
727
       sz++, size <<= 1);
728
 
729
  start_addr = (unsigned long) dmap->raw_buf;
730
  end_addr = start_addr + audio_devs[dev]->buffsize;
731
 
732
  for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
733
    {
734
      mem_map_unreserve (i);
735
    }
736
 
737
  free_pages ((unsigned long) dmap->raw_buf, sz);
738
  dmap->raw_buf = NULL;
739
}
740
 
741
int
742
sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info)
743
{
744
  printk ("Entered sound_map_buffer()\n");
745
  printk ("Exited sound_map_buffer()\n");
746
  return -(EINVAL);
747
}
748
#endif
749
 
750
void
751
conf_printf (char *name, struct address_info *hw_config)
752
{
753
  if (!trace_init)
754
    return;
755
 
756
  printk ("<%s> at 0x%03x", name, hw_config->io_base);
757
 
758
  if (hw_config->irq)
759
    printk (" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq);
760
 
761
  if (hw_config->dma != -1 || hw_config->dma2 != -1)
762
    {
763
      printk (" dma %d", hw_config->dma);
764
      if (hw_config->dma2 != -1)
765
        printk (",%d", hw_config->dma2);
766
    }
767
 
768
  printk ("\n");
769
}
770
 
771
void
772
conf_printf2 (char *name, int base, int irq, int dma, int dma2)
773
{
774
  if (!trace_init)
775
    return;
776
 
777
  printk ("<%s> at 0x%03x", name, base);
778
 
779
  if (irq)
780
    printk (" irq %d", (irq > 0) ? irq : -irq);
781
 
782
  if (dma != -1 || dma2 != -1)
783
    {
784
      printk (" dma %d", dma);
785
      if (dma2 != -1)
786
        printk (",%d", dma2);
787
    }
788
 
789
  printk ("\n");
790
}

powered by: WebSVN 2.1.0

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