/
SC_CMI.C
822 lines (698 loc) · 27 KB
/
SC_CMI.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
//**************************************************************************
//* This file is part of the *
//* Mpxplay - audio player. *
//* The source code of Mpxplay is *
//* (C) copyright 1998-2008 by PDSoft (Attila Padar) *
//* http://mpxplay.sourceforge.net *
//* email: mpxplay@freemail.hu *
//**************************************************************************
//* This program is distributed in the hope that it will be useful, *
//* but WITHOUT ANY WARRANTY; without even the implied warranty of *
//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
//* Please contact with the author (with me) if you want to use *
//* or modify this source. *
//**************************************************************************
//function: CMI 8338/8738 (PCI) low level routines
//based on the ALSA (http://www.alsa-project.org)
#include "mpxplay.h"
#ifdef AU_CARDS_LINK_CMI8X38
#include <string.h>
#include "dmairq.h"
#include "pcibios.h"
#include "ac97_def.h"
#define CMI8X38_LINK_MULTICHAN 1
#define PCMBUFFERPAGESIZE 4096
/*
* CM8x38 registers definition
*/
#define CM_REG_FUNCTRL0 0x00
#define CM_RST_CH1 0x00080000
#define CM_RST_CH0 0x00040000
#define CM_CHEN1 0x00020000 /* ch1: enable */
#define CM_CHEN0 0x00010000 /* ch0: enable */
#define CM_PAUSE1 0x00000008 /* ch1: pause */
#define CM_PAUSE0 0x00000004 /* ch0: pause */
#define CM_CHADC1 0x00000002 /* ch1, 0:playback, 1:record */
#define CM_CHADC0 0x00000001 /* ch0, 0:playback, 1:record */
#define CM_REG_FUNCTRL1 0x04
#define CM_ASFC_MASK 0x0000E000 /* ADC sampling frequency */
#define CM_ASFC_SHIFT 13
#define CM_DSFC_MASK 0x00001C00 /* DAC sampling frequency */
#define CM_DSFC_SHIFT 10
#define CM_SPDF_1 0x00000200 /* SPDIF IN/OUT at channel B */
#define CM_SPDF_0 0x00000100 /* SPDIF OUT only channel A */
#define CM_SPDFLOOP 0x00000080 /* ext. SPDIIF/OUT -> IN loopback */
#define CM_SPDO2DAC 0x00000040 /* SPDIF/OUT can be heard from internal DAC */
#define CM_INTRM 0x00000020 /* master control block (MCB) interrupt enabled */
#define CM_BREQ 0x00000010 /* bus master enabled */
#define CM_VOICE_EN 0x00000008 /* legacy voice (SB16,FM) */
#define CM_UART_EN 0x00000004 /* UART */
#define CM_JYSTK_EN 0x00000002 /* joy stick */
#define CM_REG_CHFORMAT 0x08
#define CM_CHB3D5C 0x80000000 /* 5,6 channels */
#define CM_CHB3D 0x20000000 /* 4 channels */
#define CM_CHIP_MASK1 0x1f000000
#define CM_CHIP_037 0x01000000
#define CM_SPDIF_SELECT1 0x00080000 /* for model <= 037 ? */
#define CM_AC3EN1 0x00100000 /* enable AC3: model 037 */
#define CM_SPD24SEL 0x00020000 /* 24bit spdif: model 037 */
/* #define CM_SPDIF_INVERSE 0x00010000 */ /* ??? */
#define CM_ADCBITLEN_MASK 0x0000C000
#define CM_ADCBITLEN_16 0x00000000
#define CM_ADCBITLEN_15 0x00004000
#define CM_ADCBITLEN_14 0x00008000
#define CM_ADCBITLEN_13 0x0000C000
#define CM_ADCDACLEN_MASK 0x00003000
#define CM_ADCDACLEN_060 0x00000000
#define CM_ADCDACLEN_066 0x00001000
#define CM_ADCDACLEN_130 0x00002000
#define CM_ADCDACLEN_280 0x00003000
#define CM_CH1_SRATE_176K 0x00000800
#define CM_CH1_SRATE_88K 0x00000400
#define CM_CH0_SRATE_176K 0x00000200
#define CM_CH0_SRATE_88K 0x00000100
#define CM_SPDIF_INVERSE2 0x00000080 /* model 055? */
#define CM_CH1FMT_MASK 0x0000000C
#define CM_CH1FMT_SHIFT 2
#define CM_CH0FMT_MASK 0x00000003
#define CM_CH0FMT_SHIFT 0
#define CM_REG_INT_HLDCLR 0x0C
#define CM_CHIP_MASK2 0xff000000
#define CM_CHIP_039 0x04000000
#define CM_CHIP_039_6CH 0x01000000
#define CM_TDMA_INT_EN 0x00040000
#define CM_CH1_INT_EN 0x00020000
#define CM_CH0_INT_EN 0x00010000
#define CM_INT_HOLD 0x00000002
#define CM_INT_CLEAR 0x00000001
#define CM_REG_INT_STATUS 0x10
#define CM_INTR 0x80000000
#define CM_VCO 0x08000000 /* Voice Control? CMI8738 */
#define CM_MCBINT 0x04000000 /* Master Control Block abort cond.? */
#define CM_UARTINT 0x00010000
#define CM_LTDMAINT 0x00008000
#define CM_HTDMAINT 0x00004000
#define CM_XDO46 0x00000080 /* Modell 033? Direct programming EEPROM (read data register) */
#define CM_LHBTOG 0x00000040 /* High/Low status from DMA ctrl register */
#define CM_LEG_HDMA 0x00000020 /* Legacy is in High DMA channel */
#define CM_LEG_STEREO 0x00000010 /* Legacy is in Stereo mode */
#define CM_CH1BUSY 0x00000008
#define CM_CH0BUSY 0x00000004
#define CM_CHINT1 0x00000002
#define CM_CHINT0 0x00000001
#define CM_REG_LEGACY_CTRL 0x14
#define CM_NXCHG 0x80000000 /* h/w multi channels? */
#define CM_VMPU_MASK 0x60000000 /* MPU401 i/o port address */
#define CM_VMPU_330 0x00000000
#define CM_VMPU_320 0x20000000
#define CM_VMPU_310 0x40000000
#define CM_VMPU_300 0x60000000
#define CM_VSBSEL_MASK 0x0C000000 /* SB16 base address */
#define CM_VSBSEL_220 0x00000000
#define CM_VSBSEL_240 0x04000000
#define CM_VSBSEL_260 0x08000000
#define CM_VSBSEL_280 0x0C000000
#define CM_FMSEL_MASK 0x03000000 /* FM OPL3 base address */
#define CM_FMSEL_388 0x00000000
#define CM_FMSEL_3C8 0x01000000
#define CM_FMSEL_3E0 0x02000000
#define CM_FMSEL_3E8 0x03000000
#define CM_ENSPDOUT 0x00800000 /* enable XPDIF/OUT to I/O interface */
#define CM_SPDCOPYRHT 0x00400000 /* set copyright spdif in/out */
#define CM_DAC2SPDO 0x00200000 /* enable wave+fm_midi -> SPDIF/OUT */
#define CM_SETRETRY 0x00010000 /* 0: legacy i/o wait (default), 1: legacy i/o bus retry */
#define CM_CHB3D6C 0x00008000 /* 5.1 channels support */
#define CM_LINE_AS_BASS 0x00006000 /* use line-in as bass */
#define CM_REG_MISC_CTRL 0x18
#define CM_PWD 0x80000000
#define CM_RESET 0x40000000
#define CM_SFIL_MASK 0x30000000
#define CM_TXVX 0x08000000
#define CM_N4SPK3D 0x04000000 /* 4ch output */
#define CM_SPDO5V 0x02000000 /* 5V spdif output (1 = 0.5v (coax)) */
#define CM_SPDIF48K 0x01000000 /* write */
#define CM_SPATUS48K 0x01000000 /* read */
#define CM_ENDBDAC 0x00800000 /* enable dual dac */
#define CM_XCHGDAC 0x00400000 /* 0: front=ch0, 1: front=ch1 */
#define CM_SPD32SEL 0x00200000 /* 0: 16bit SPDIF, 1: 32bit */
#define CM_SPDFLOOPI 0x00100000 /* int. SPDIF-IN -> int. OUT */
#define CM_FM_EN 0x00080000 /* enalbe FM */
#define CM_AC3EN2 0x00040000 /* enable AC3: model 039 */
#define CM_VIDWPDSB 0x00010000
#define CM_SPDF_AC97 0x00008000 /* 0: SPDIF/OUT 44.1K, 1: 48K */
#define CM_MASK_EN 0x00004000
#define CM_VIDWPPRT 0x00002000
#define CM_SFILENB 0x00001000
#define CM_MMODE_MASK 0x00000E00
#define CM_SPDIF_SELECT2 0x00000100 /* for model > 039 ? */
#define CM_ENCENTER 0x00000080
#define CM_FLINKON 0x00000040
#define CM_FLINKOFF 0x00000020
#define CM_MIDSMP 0x00000010
#define CM_UPDDMA_MASK 0x0000000C
#define CM_TWAIT_MASK 0x00000003
/* byte */
#define CM_REG_MIXER0 0x20
#define CM_REG_SB16_DATA 0x22
#define CM_REG_SB16_ADDR 0x23
#define CM_REFFREQ_XIN (315*1000*1000)/22 /* 14.31818 Mhz reference clock frequency pin XIN */
#define CM_ADCMULT_XIN 512 /* Guessed (487 best for 44.1kHz, not for 88/176kHz) */
#define CM_TOLERANCE_RATE 0.001 /* Tolerance sample rate pitch (1000ppm) */
#define CM_MAXIMUM_RATE 80000000 /* Note more than 80MHz */
#define CM_REG_MIXER1 0x24
#define CM_FMMUTE 0x80 /* mute FM */
#define CM_FMMUTE_SHIFT 7
#define CM_WSMUTE 0x40 /* mute PCM */
#define CM_WSMUTE_SHIFT 6
#define CM_SPK4 0x20 /* lin-in -> rear line out */
#define CM_SPK4_SHIFT 5
#define CM_REAR2FRONT 0x10 /* exchange rear/front */
#define CM_REAR2FRONT_SHIFT 4
#define CM_WAVEINL 0x08 /* digital wave rec. left chan */
#define CM_WAVEINL_SHIFT 3
#define CM_WAVEINR 0x04 /* digical wave rec. right */
#define CM_WAVEINR_SHIFT 2
#define CM_X3DEN 0x02 /* 3D surround enable */
#define CM_X3DEN_SHIFT 1
#define CM_CDPLAY 0x01 /* enable SPDIF/IN PCM -> DAC */
#define CM_CDPLAY_SHIFT 0
#define CM_REG_MIXER2 0x25
#define CM_RAUXREN 0x80 /* AUX right capture */
#define CM_RAUXREN_SHIFT 7
#define CM_RAUXLEN 0x40 /* AUX left capture */
#define CM_RAUXLEN_SHIFT 6
#define CM_VAUXRM 0x20 /* AUX right mute */
#define CM_VAUXRM_SHIFT 5
#define CM_VAUXLM 0x10 /* AUX left mute */
#define CM_VAUXLM_SHIFT 4
#define CM_VADMIC_MASK 0x0e /* mic gain level (0-3) << 1 */
#define CM_VADMIC_SHIFT 1
#define CM_MICGAINZ 0x01 /* mic boost */
#define CM_MICGAINZ_SHIFT 0
#define CM_REG_AUX_VOL 0x26
#define CM_VAUXL_MASK 0xf0
#define CM_VAUXR_MASK 0x0f
#define CM_REG_MISC 0x27
#define CM_XGPO1 0x20
// #define CM_XGPBIO 0x04
#define CM_MIC_CENTER_LFE 0x04 /* mic as center/lfe out? (model 039 or later?) */
#define CM_SPDIF_INVERSE 0x04 /* spdif input phase inverse (model 037) */
#define CM_SPDVALID 0x02 /* spdif input valid check */
#define CM_DMAUTO 0x01
#define CM_REG_AC97 0x28 /* hmmm.. do we have ac97 link? */
/*
* For CMI-8338 (0x28 - 0x2b) .. is this valid for CMI-8738
* or identical with AC97 codec?
*/
#define CM_REG_EXTERN_CODEC CM_REG_AC97
/*
* MPU401 pci port index address 0x40 - 0x4f (CMI-8738 spec ver. 0.6)
*/
#define CM_REG_MPU_PCI 0x40
/*
* FM pci port index address 0x50 - 0x5f (CMI-8738 spec ver. 0.6)
*/
#define CM_REG_FM_PCI 0x50
/*
* for CMI-8338 .. this is not valid for CMI-8738.
*/
#define CM_REG_EXTENT_IND 0xf0
#define CM_VPHONE_MASK 0xe0 /* Phone volume control (0-3) << 5 */
#define CM_VPHONE_SHIFT 5
#define CM_VPHOM 0x10 /* Phone mute control */
#define CM_VSPKM 0x08 /* Speaker mute control, default high */
#define CM_RLOOPREN 0x04 /* Rec. R-channel enable */
#define CM_RLOOPLEN 0x02 /* Rec. L-channel enable */
/*
* CMI-8338 spec ver 0.5 (this is not valid for CMI-8738):
* the 8 registers 0xf8 - 0xff are used for programming m/n counter by the PLL
* unit (readonly?).
*/
#define CM_REG_PLL 0xf8
/*
* extended registers
*/
#define CM_REG_CH0_FRAME1 0x80 /* base address */
#define CM_REG_CH0_FRAME2 0x84
#define CM_REG_CH1_FRAME1 0x88 /* 0-15: count of samples at bus master; buffer size */
#define CM_REG_CH1_FRAME2 0x8C /* 16-31: count of samples at codec; fragment size */
/*
* size of i/o region
*/
#define CM_EXTENT_CODEC 0x100
#define CM_EXTENT_MIDI 0x2
#define CM_EXTENT_SYNTH 0x4
/* fixed legacy joystick address */
#define CM_JOYSTICK_ADDR 0x200
/*
* pci ids
*/
#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111
#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112
/*
* channels for playback / capture
*/
#define CM_CH_PLAY 0
#define CM_CH_CAPT 1
/*
* flags to check device open/close
*/
#define CM_OPEN_NONE 0
#define CM_OPEN_CH_MASK 0x01
#define CM_OPEN_DAC 0x10
#define CM_OPEN_ADC 0x20
#define CM_OPEN_SPDIF 0x40
#define CM_OPEN_MCHAN 0x80
#define CM_OPEN_PLAYBACK (CM_CH_PLAY | CM_OPEN_DAC)
#define CM_OPEN_PLAYBACK2 (CM_CH_CAPT | CM_OPEN_DAC)
#define CM_OPEN_PLAYBACK_MULTI (CM_CH_PLAY | CM_OPEN_DAC | CM_OPEN_MCHAN)
#define CM_OPEN_CAPTURE (CM_CH_CAPT | CM_OPEN_ADC)
#define CM_OPEN_SPDIF_PLAYBACK (CM_CH_PLAY | CM_OPEN_DAC | CM_OPEN_SPDIF)
#define CM_OPEN_SPDIF_CAPTURE (CM_CH_CAPT | CM_OPEN_ADC | CM_OPEN_SPDIF)
#if CM_CH_PLAY == 1
#define CM_PLAYBACK_SRATE_176K CM_CH1_SRATE_176K
#define CM_PLAYBACK_SPDF CM_SPDF_1
#define CM_CAPTURE_SPDF CM_SPDF_0
#else
#define CM_PLAYBACK_SRATE_176K CM_CH0_SRATE_176K
#define CM_PLAYBACK_SPDF CM_SPDF_0
#define CM_CAPTURE_SPDF CM_SPDF_1
#endif
typedef struct cmi8x38_card
{
unsigned long iobase;
unsigned short model;
unsigned int irq;
unsigned char chiprev;
unsigned char device_type;
struct pci_config_s *pci_dev;
dosmem_t *dm;
char *pcmout_buffer;
long pcmout_bufsize;
unsigned int ctrl;
int chip_version;
int max_channels;
//unsigned int has_dual_dac;
//unsigned int can_ac3_sw;
//unsigned int can_ac3_hw;
unsigned int can_multi_ch;
//unsigned int do_soft_ac3;
//unsigned int spdif_playback_avail; /* spdif ready? */
//unsigned int spdif_playback_enabled; /* spdif switch enabled? */
//int spdif_counter; /* for software AC3 */
//unsigned int dig_status;
//unsigned int dig_pcm_status;
unsigned int dma_size; /* in frames */
unsigned int period_size; /* in frames */
unsigned int fmt; /* format bits */
//int bytes_per_frame;
int shift;
//int ac3_shift; /* extra shift: 1 on soft ac3 mode */
}cmi8x38_card;
static void cmi8x38_ac97_write(unsigned int baseport,unsigned int reg, unsigned int value);
static unsigned int cmi8x38_ac97_read(unsigned int baseport, unsigned int reg);
extern unsigned int intsoundconfig,intsoundcontrol;
//-------------------------------------------------------------------------
// low level write & read
#define snd_cmipci_write_8(cm,reg,data) outb(cm->iobase+reg,data)
#define snd_cmipci_write_16(cm,reg,data) outw(cm->iobase+reg,data)
#define snd_cmipci_write_32(cm,reg,data) outl(cm->iobase+reg,data)
#define snd_cmipci_read_8(cm,reg) inb(cm->iobase+reg)
#define snd_cmipci_read_16(cm,reg) inw(cm->iobase+reg)
#define snd_cmipci_read_32(cm,reg) inl(cm->iobase+reg)
static void snd_cmipci_set_bit(cmi8x38_card *cm, unsigned int cmd, unsigned int flag)
{
unsigned int val;
val = snd_cmipci_read_32(cm, cmd);
val|= flag;
snd_cmipci_write_32(cm, cmd, val);
}
static void snd_cmipci_clear_bit(cmi8x38_card *cm, unsigned int cmd, unsigned int flag)
{
unsigned int val;
val = snd_cmipci_read_32(cm, cmd);
val&= ~flag;
snd_cmipci_write_32(cm, cmd, val);
}
static void snd_cmipci_mixer_write(cmi8x38_card *cm, unsigned char idx, unsigned char data)
{
snd_cmipci_write_8(cm, CM_REG_SB16_ADDR, idx);
snd_cmipci_write_8(cm, CM_REG_SB16_DATA, data);
}
static unsigned int snd_cmipci_mixer_read(cmi8x38_card *cm, unsigned char idx)
{
snd_cmipci_write_8(cm, CM_REG_SB16_ADDR, idx);
return snd_cmipci_read_8(cm, CM_REG_SB16_DATA);
}
//-------------------------------------------------------------------------
static unsigned int cmi_rates[] = { 5512, 11025, 22050, 44100, 8000, 16000, 32000, 48000 };
static unsigned int snd_cmipci_rate_freq(unsigned int rate)
{
unsigned int i;
for(i = 0; i < 8; i++) {
if(cmi_rates[i] == rate)
return i;
}
return 7; // 48k
}
static void snd_cmipci_ch_reset(cmi8x38_card *cm, int ch)
{
int reset = CM_RST_CH0 << ch;
snd_cmipci_write_32(cm, CM_REG_FUNCTRL0, CM_CHADC0 | reset);
snd_cmipci_write_32(cm, CM_REG_FUNCTRL0, CM_CHADC0 & (~reset));
pds_delay_10us(1);
}
static int set_dac_channels(cmi8x38_card *cm, int channels)
{
/*if(channels > 2){
if(!cm->can_multi_ch)
return -1;
if(cm->fmt != 0x03) // stereo 16bit only
return -1;
snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG);
if(channels > 4){
snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D);
snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C);
}else{
snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C);
snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D);
}
if(channels == 6){
snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C);
snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER);
}else{
snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C);
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER);
}
}else{*/
if(cm->can_multi_ch){
snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG);
snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D);
snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C);
snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C);
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER);
}
//}
return 0;
}
static void query_chip(cmi8x38_card *cm)
{
unsigned int detect;
/* check reg 0Ch, bit 24-31 */
detect = snd_cmipci_read_32(cm, CM_REG_INT_HLDCLR) & CM_CHIP_MASK2;
if(!detect){
/* check reg 08h, bit 24-28 */
detect = snd_cmipci_read_32(cm, CM_REG_CHFORMAT) & CM_CHIP_MASK1;
if(!detect) {
cm->chip_version = 33;
cm->max_channels = 2;
//if(cm->do_soft_ac3)
// cm->can_ac3_sw = 1;
//else
// cm->can_ac3_hw = 1;
//cm->has_dual_dac = 1;
}else{
cm->chip_version = 37;
cm->max_channels = 2;
//cm->can_ac3_hw = 1;
//cm->has_dual_dac = 1;
}
}else{
/* check reg 0Ch, bit 26 */
if(detect&CM_CHIP_039){
cm->chip_version = 39;
if(detect & CM_CHIP_039_6CH)
cm->max_channels = 6;
else
cm->max_channels = 4;
//cm->can_ac3_hw = 1;
//cm->has_dual_dac = 1;
cm->can_multi_ch = 1;
}else{
cm->chip_version = 55; /* 4 or 6 channels */
cm->max_channels = 6;
//cm->can_ac3_hw = 1;
//cm->has_dual_dac = 1;
cm->can_multi_ch = 1;
}
}
}
static void cmi8x38_chip_init(struct cmi8x38_card *cm)
{
unsigned int val;
cm->ctrl = 0; // ch0 playback
query_chip(cm);
/* initialize codec registers */
snd_cmipci_write_32(cm, CM_REG_INT_HLDCLR, 0); /* disable ints */
snd_cmipci_ch_reset(cm, CM_CH_PLAY);
snd_cmipci_ch_reset(cm, CM_CH_CAPT);
snd_cmipci_write_32(cm, CM_REG_FUNCTRL0, 0); /* disable channels */
snd_cmipci_write_32(cm, CM_REG_FUNCTRL1, 0);
snd_cmipci_write_32(cm, CM_REG_CHFORMAT, 0);
snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC|CM_N4SPK3D);
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC);
/* Set Bus Master Request */
snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_BREQ);
/* Assume TX and compatible chip set (Autodetection required for VX chip sets) */
switch(cm->pci_dev->device_id) {
case PCI_DEVICE_ID_CMEDIA_CM8738:
case PCI_DEVICE_ID_CMEDIA_CM8738B:
/* PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX */
if(pcibios_FindDevice(0x8086, 0x7030,NULL)==PCI_SUCCESSFUL)
snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_TXVX);
break;
}
/* disable FM */
val = snd_cmipci_read_32(cm, CM_REG_LEGACY_CTRL) & (~CM_FMSEL_MASK);
snd_cmipci_write_32(cm, CM_REG_LEGACY_CTRL, val);
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_FM_EN);
/* reset mixer */
snd_cmipci_mixer_write(cm, 0, 0);
}
static void cmi8x38_chip_close(struct cmi8x38_card *cm)
{
if(cm->iobase){
snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_FM_EN);
snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_ENSPDOUT);
snd_cmipci_write_32(cm, CM_REG_INT_HLDCLR, 0); /* disable ints */
snd_cmipci_ch_reset(cm, CM_CH_PLAY);
snd_cmipci_ch_reset(cm, CM_CH_CAPT);
snd_cmipci_write_32(cm, CM_REG_FUNCTRL0, 0); /* disable channels */
snd_cmipci_write_32(cm, CM_REG_FUNCTRL1, 0);
/* reset mixer */
snd_cmipci_mixer_write(cm, 0, 0);
}
}
//-------------------------------------------------------------------------
static pci_device_s cmi_devices[]={
{"8338A",0x13F6,0x0100},
{"8338B",0x13F6,0x0101},
{"8738" ,0x13F6,0x0111},
{"8738B",0x13F6,0x0112},
{NULL,0,0}
};
static void CMI8X38_close(struct mpxplay_audioout_info_s *aui);
static void CMI8X38_card_info(struct mpxplay_audioout_info_s *aui)
{
struct cmi8x38_card *card=aui->card_private_data;
char sout[100];
sprintf(sout,"CMI : %s soundcard found on port:%4.4X irq:%d chipver:%d max-chans:%d",
card->pci_dev->device_name,card->iobase,card->irq,card->chip_version,card->max_channels);
pds_textdisplay_printf(sout);
}
static int CMI8X38_adetect(struct mpxplay_audioout_info_s *aui)
{
struct cmi8x38_card *card;
card=(struct cmi8x38_card *)pds_calloc(1,sizeof(struct cmi8x38_card));
if(!card)
return 0;
aui->card_private_data=card;
card->pci_dev=(struct pci_config_s *)pds_calloc(1,sizeof(struct pci_config_s));
if(!card->pci_dev)
goto err_adetect;
if(pcibios_search_devices(&cmi_devices,card->pci_dev)!=PCI_SUCCESSFUL)
goto err_adetect;
pcibios_set_master(card->pci_dev);
card->iobase = pcibios_ReadConfig_Dword(card->pci_dev, PCIR_NAMBAR)&0xfff0;
if(!card->iobase)
goto err_adetect;
card->irq = pcibios_ReadConfig_Byte(card->pci_dev, PCIR_INTR_LN);
card->chiprev=pcibios_ReadConfig_Byte(card->pci_dev, PCIR_RID);
card->model =pcibios_ReadConfig_Word(card->pci_dev, PCIR_SSID);
// alloc buffers
card->pcmout_bufsize=MDma_get_max_pcmoutbufsize(aui,0,PCMBUFFERPAGESIZE,2,0);
card->dm=MDma_alloc_cardmem( card->pcmout_bufsize // pcm output
+PCMBUFFERPAGESIZE ); // to round
card->pcmout_buffer=(void *)(((uint32_t)card->dm->linearptr+PCMBUFFERPAGESIZE-1)&(~(PCMBUFFERPAGESIZE-1))); // buffer begins on page (4096 bytes) boundary
aui->card_DMABUFF=card->pcmout_buffer;
// init chip
cmi8x38_chip_init(card);
return 1;
err_adetect:
CMI8X38_close(aui);
return 0;
}
static void CMI8X38_close(struct mpxplay_audioout_info_s *aui)
{
struct cmi8x38_card *card=aui->card_private_data;
if(card){
if(card->iobase)
cmi8x38_chip_close(card);
MDma_free_cardmem(card->dm);
if(card->pci_dev)
pds_free(card->pci_dev);
pds_free(card);
aui->card_private_data=NULL;
}
}
static void CMI8X38_setrate(struct mpxplay_audioout_info_s *aui)
{
struct cmi8x38_card *card=aui->card_private_data;
unsigned int dmabufsize,val,freqnum;
if(aui->freq_card<5512)
aui->freq_card=5512;
else{
if(aui->freq_card>48000)
aui->freq_card=48000;
}
aui->chan_card=2;
aui->bits_card=16;
aui->card_wave_id=MPXPLAY_WAVEID_PCM_SLE;
dmabufsize=MDma_init_pcmoutbuf(aui,card->pcmout_bufsize,PCMBUFFERPAGESIZE,0);
//hw config
//reset dac, disable ch
card->ctrl &= ~CM_CHEN0;
snd_cmipci_write_32(card, CM_REG_FUNCTRL0, card->ctrl | CM_RST_CH0);
snd_cmipci_write_32(card, CM_REG_FUNCTRL0, card->ctrl & ~CM_RST_CH0);
//format cfg
card->fmt=0;
card->shift=0;
if(aui->bits_card>=16){
card->fmt|=0x02;
card->shift++;
//if(aui->bits_card>16) // 24,32 bits ???
// card->shift++;
}
if(aui->chan_card>1){
card->fmt|=0x01;
card->shift++;
}
//
if(set_dac_channels(card,aui->chan_card)!=0)
return;
//buffer cfg
card->dma_size = dmabufsize >> card->shift;
card->period_size = dmabufsize >> card->shift;
//card->dma_size >>= card->ac3_shift;
//card->period_size >>= card->ac3_shift;
//if(aui->chan_card>2){
// card->dma_size = (card->dma_size * aui->chan_card) / 2;
// card->period_size = (card->period_size * aui->chan_card) / 2;
//}
// set buffer address
snd_cmipci_write_32(card, CM_REG_CH0_FRAME1, (long)card->pcmout_buffer);
// program sample counts
snd_cmipci_write_16(card, CM_REG_CH0_FRAME2 , card->dma_size - 1);
snd_cmipci_write_16(card, CM_REG_CH0_FRAME2 + 2, card->period_size - 1);
// set sample rate
freqnum = snd_cmipci_rate_freq(aui->freq_card);
aui->freq_card=cmi_rates[freqnum]; // if the freq-config is not standard at CMI
val = snd_cmipci_read_32(card, CM_REG_FUNCTRL1);
val &= ~CM_DSFC_MASK;
val |= (freqnum << CM_DSFC_SHIFT) & CM_DSFC_MASK;
snd_cmipci_write_32(card, CM_REG_FUNCTRL1, val);
// set format
val = snd_cmipci_read_32(card, CM_REG_CHFORMAT);
val &= ~CM_CH0FMT_MASK;
val |= card->fmt << CM_CH0FMT_SHIFT;
snd_cmipci_write_32(card, CM_REG_CHFORMAT, val);
// set SPDIF
//if((aui->freq_card==44100 || aui->freq_card==48000) && (aui->chan_card==2) && (aui->bits_card==16))
// snd_cmipci_set_bit(card, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF);
//else
snd_cmipci_clear_bit(card, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF);
}
static void CMI8X38_start(struct mpxplay_audioout_info_s *aui)
{
struct cmi8x38_card *card=aui->card_private_data;
card->ctrl |= CM_CHEN0;
card->ctrl &= ~CM_PAUSE0;
snd_cmipci_write_32(card, CM_REG_FUNCTRL0, card->ctrl);
}
static void CMI8X38_stop(struct mpxplay_audioout_info_s *aui)
{
struct cmi8x38_card *card=aui->card_private_data;
card->ctrl |= CM_PAUSE0;
snd_cmipci_write_32(card, CM_REG_FUNCTRL0, card->ctrl);
}
static long CMI8X38_getbufpos(struct mpxplay_audioout_info_s *aui)
{
struct cmi8x38_card *card=aui->card_private_data;
unsigned long bufpos;
bufpos = snd_cmipci_read_16(card, CM_REG_CH0_FRAME2);
if(bufpos && (bufpos<=card->dma_size)){
bufpos = card->dma_size -bufpos;
bufpos <<= card->shift;
//bufpos <<= card->ac3_shift;
//if(aui->chan_card > 2)
// bufpos = (bufpos * 2) / aui->chan_card;
if(bufpos<aui->card_dmasize)
aui->card_dma_lastgoodpos=bufpos;
}
return aui->card_dma_lastgoodpos;
}
static void CMI8X38_clearbuf(struct mpxplay_audioout_info_s *aui)
{
MDma_clearbuf(aui);
}
//--------------------------------------------------------------------------
//mixer
static void CMI8X38_writeMIXER(struct mpxplay_audioout_info_s *aui,unsigned long reg, unsigned long val)
{
struct cmi8x38_card *card=aui->card_private_data;
snd_cmipci_mixer_write(card,reg,val);
}
static unsigned long CMI8X38_readMIXER(struct mpxplay_audioout_info_s *aui,unsigned long reg)
{
struct cmi8x38_card *card=aui->card_private_data;
return snd_cmipci_mixer_read(card,reg);
}
//like SB16
static aucards_onemixerchan_s cmi8x38_master_vol={AU_MIXCHANFUNCS_PACK(AU_MIXCHAN_MASTER,AU_MIXCHANFUNC_VOLUME),2,{{0x30,31,3,0},{0x31,31,3,0}}};
static aucards_onemixerchan_s cmi8x38_pcm_vol={AU_MIXCHANFUNCS_PACK(AU_MIXCHAN_PCM,AU_MIXCHANFUNC_VOLUME), 2,{{0x32,31,3,0},{0x33,31,3,0}}};
static aucards_onemixerchan_s cmi8x38_synth_vol={AU_MIXCHANFUNCS_PACK(AU_MIXCHAN_SYNTH,AU_MIXCHANFUNC_VOLUME), 2,{{0x34,31,3,0},{0x35,31,3,0}}};
static aucards_onemixerchan_s cmi8x38_cdin_vol={AU_MIXCHANFUNCS_PACK(AU_MIXCHAN_CDIN,AU_MIXCHANFUNC_VOLUME), 2,{{0x36,31,3,0},{0x37,31,3,0}}};
static aucards_onemixerchan_s cmi8x38_linein_vol={AU_MIXCHANFUNCS_PACK(AU_MIXCHAN_LINEIN,AU_MIXCHANFUNC_VOLUME),2,{{0x38,31,3,0},{0x39,31,3,0}}};
static aucards_onemixerchan_s cmi8x38_micin_vol={AU_MIXCHANFUNCS_PACK(AU_MIXCHAN_MICIN,AU_MIXCHANFUNC_VOLUME), 1,{{0x3A,31,3,0}}};
static aucards_onemixerchan_s cmi8x38_auxin_vol={AU_MIXCHANFUNCS_PACK(AU_MIXCHAN_AUXIN,AU_MIXCHANFUNC_VOLUME), 2,{{0x26,15,4,0},{0x26,15,0,0}}}; //??? in or out?
static aucards_allmixerchan_s cmi8x38_mixerset[]={
&cmi8x38_master_vol,
&cmi8x38_pcm_vol,
&cmi8x38_synth_vol,
&cmi8x38_cdin_vol,
&cmi8x38_linein_vol,
&cmi8x38_micin_vol,
&cmi8x38_auxin_vol,
NULL
};
one_sndcard_info CMI8X38_sndcard_info={
"CMI",
SNDCARD_LOWLEVELHAND|SNDCARD_INT08_ALLOWED,
NULL,
NULL, // no init
&CMI8X38_adetect, // only autodetect
&CMI8X38_card_info,
&CMI8X38_start,
&CMI8X38_stop,
&CMI8X38_close,
&CMI8X38_setrate,
&MDma_writedata,
&CMI8X38_getbufpos,
&CMI8X38_clearbuf,
&MDma_interrupt_monitor,
NULL,
&CMI8X38_writeMIXER,
&CMI8X38_readMIXER,
&cmi8x38_mixerset[0]
};
#endif