⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ad1848.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		m, ad_read(d, 9) ) ;	if (wr || ! FULL_DUPLEX(d) )	    ad_write_cnt(d, 14, cnt);	else	    ad_write_cnt(d, 30, cnt);	break ;    case SND_CB_STOP :    case SND_CB_ABORT : /* XXX check this... */	m = ad_read(d,9) ;	m &= wr ?  ~I9_PEN : ~I9_CEN ; /* Stop DMA */	/*	 * on the OPTi931 the enable bit seems hard to set...	 */	for (retry = 10; retry ; retry-- ) {	    ad_write(d, 9, m );	    if (ad_read(d,9) ==m) break;	}	if (retry == 0)	    printf("start dma, failed to clear bit 0x%02x 0x%02x\n",		m, ad_read(d, 9) ) ;#if 1	/*	 * try to disable DMA by clearing count registers. Not sure it	 * is needed, and it might cause false interrupts when the	 * DMA is re-enabled later.	 */	if (wr || ! FULL_DUPLEX(d) )	    ad_write_cnt(d, 14, 0);	else	    ad_write_cnt(d, 30, 0);	break;#endif    }    return 0 ;}/* * main irq handler for the CS423x. The OPTi931 code is * a separate one. * The correct way to operate for a device with multiple internal * interrupt sources is to loop on the status register and ack * interrupts until all interrupts are served and none are reported. At * this point the IRQ line to the ISA IRQ controller should go low * and be raised at the next interrupt. * * Since the ISA IRQ controller is sent EOI _before_ passing control * to the isr, it might happen that we serve an interrupt early, in * which case the status register at the next interrupt should just * say that there are no more interrupts... */static voidmss_intr(int unit){    snddev_info *d = &pcm_info[unit];    u_char c, served = 0;    int i;    DEB(printf("mss_intr\n"));    ad_read(d, 11); /* fake read of status bits */    /*     * loop until there are interrupts, but no more than 10 times.     */    for (i=10 ; i && inb(io_Status(d)) & 1 ; i-- ) {	/* get exact reason for full-duplex boards */	c = FULL_DUPLEX(d) ? ad_read(d, 24) : 0x30 ;	c &= ~served ;	if ( d->dbuf_out.dl && (c & 0x10) ) {	    served |= 0x10 ;	    dsp_wrintr(d);	}	if ( d->dbuf_in.dl && (c & 0x20) ) {	    served |= 0x20 ;	    dsp_rdintr(d);	}	/* 	 * now ack the interrupt	 */	if ( FULL_DUPLEX(d) )	    ad_write(d, 24, ~c); /* ack selectively */	else	    outb(io_Status(d), 0);	/* Clear interrupt status */    }    if (served == 0) {	printf("How strange... mss_intr with no reason!\n");	/*	 * this should not happen... I have no idea what to do now.	 * maybe should do a sanity check and restart dmas ?	 */	outb(io_Status(d), 0);	/* Clear interrupt status */    }}/* * the opti931 seems to miss interrupts when working in full * duplex, so we try some heuristics to catch them. */static voidopti931_intr(int unit){    snddev_info *d = &pcm_info[unit];    u_char masked=0, i11, mc11, c=0;    u_char reason; /* b0 = playback, b1 = capture, b2 = timer */    int loops = 10;#if 0    reason = inb(io_Status(d));    if ( ! (reason & 1) ) {/* no int, maybe a shared line ? */	printf("opti931_intr: flag 0, mcir11 0x%02x\n", ad_read(d,11));	return;    }#endif    i11 = ad_read(d, 11); /* XXX what's for ? */again:    c=mc11 = FULL_DUPLEX(d) ? opti_read(d->conf_base, 11) : 0xc ;    mc11 &= 0x0c ;    if (c & 0x10) {	DEB(printf("Warning: CD interrupt\n");)	mc11 |= 0x10 ;    }    if (c & 0x20) {	DEB(printf("Warning: MPU interrupt\n");)	mc11 |= 0x20 ;    }    if (mc11 & masked)         printf("irq reset failed, mc11 0x%02x, masked 0x%02x\n", mc11, masked);    masked |= mc11 ;    /*     * the nice OPTi931 sets the IRQ line before setting the bits in     * mc11. So, on some occasions I have to retry (max 10 times).     */    if ( mc11 == 0 ) { /* perhaps can return ... */	reason = inb(io_Status(d));	if (reason & 1) {	    DEB(printf("one more try...\n");)	    if (--loops)		goto again;	    else		DDB(printf("opti_intr: irq but mc11 not set!...\n");)	}	if (loops==10)	    printf("ouch, intr but nothing in mcir11 0x%02x\n", mc11);	return;    }    if ( d->dbuf_in.dl && (mc11 & 8) ) {	dsp_rdintr(d);    }    if ( d->dbuf_out.dl && (mc11 & 4) ) {	dsp_wrintr(d);    }    opti_write(d->conf_base, 11, ~mc11); /* ack */    if (--loops)	goto again;    DEB(printf("xxx too many loops\n");)}/* * Second part of the file: functions local to this module. * in this section a few routines to access MSS registers * */static voidopti_write(int io_base, u_char reg, u_char value){    outb(io_base, reg);    outb(io_base+1, value);}static u_charopti_read(int io_base, u_char reg){    outb(io_base, reg);    return inb(io_base+1);}static voidgus_write(int io_base, u_char reg, u_char value){    outb(io_base + 3, reg);    outb(io_base + 5, value);}static voidgus_writew(int io_base, u_char reg, u_short value){    outb(io_base + 3, reg);    outb(io_base + 4, value);}static u_chargus_read(int io_base, u_char reg){    outb(io_base+3, reg);    return inb(io_base+5);}static u_shortgus_readw(int io_base, u_char reg){    outb(io_base+3, reg);    return inw(io_base+4);}/* * AD_WAIT_INIT waits if we are initializing the board and * we cannot modify its settings */static intAD_WAIT_INIT(snddev_info *d, int x){    int arg=x, n = 0; /* to shut up the compiler... */    for (; x-- ; )	if ( (n=inb(io_Index_Addr(d))) & IA_BUSY)	    DELAY(10);	else	    return n ;    printf("AD_WAIT_INIT FAILED %d 0x%02x\n", arg, n);    return n ;}static intad_read(snddev_info *d, int reg){    u_long   flags;    int             x;    flags = spltty();    AD_WAIT_INIT(d, 201);    x = inb(io_Index_Addr(d)) & ~IA_AMASK ;    outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ;    x = inb(io_Indexed_Data(d));    splx(flags);    return x;}static voidad_write(snddev_info *d, int reg, u_char data){    u_long   flags;    int x ;    flags = spltty();    AD_WAIT_INIT(d, 1002);    x = inb(io_Index_Addr(d)) & ~IA_AMASK ;    outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ;    outb(io_Indexed_Data(d), data);    splx(flags);}static voidad_write_cnt(snddev_info *d, int reg, u_short cnt){    ad_write(d, reg+1, cnt & 0xff );    ad_write(d, reg, cnt >> 8 ); /* upper base must be last */}static voidwait_for_calibration(snddev_info *d){    int n, t;    /*     * Wait until the auto calibration process has finished.     *      * 1) Wait until the chip becomes ready (reads don't return 0x80).     * 2) Wait until the ACI bit of I11 gets on     * 3) Wait until the ACI bit of I11 gets off     */    n = AD_WAIT_INIT(d, 1000);    if (n & IA_BUSY)	printf("mss: Auto calibration timed out(1).\n");    for (t = 100 ; t>0 && (ad_read(d, 11) & 0x20) == 0 ; t--)	    DELAY(100);    for (t = 100 ; t>0 && ad_read(d, 11) & 0x20 ; t--)	    DELAY(100);}#if 0 /* unused right now... */static voidad_mute(snddev_info *d){    ad_write(d, 6, ad_read(d,6) | I6_MUTE);    ad_write(d, 7, ad_read(d,7) | I6_MUTE);}static voidad_unmute(snddev_info *d){    ad_write(d, 6, ad_read(d,6) & ~I6_MUTE);    ad_write(d, 7, ad_read(d,7) & ~I6_MUTE);}#endifstatic voidad_enter_MCE(snddev_info *d){    int prev;    d->bd_flags |= BD_F_MCE_BIT;    AD_WAIT_INIT(d, 203);    prev = inb(io_Index_Addr(d));    prev &= ~IA_TRD ;    outb(io_Index_Addr(d), prev | IA_MCE ) ;}static voidad_leave_MCE(snddev_info *d){    u_long   flags;    u_char   prev;    if ( (d->bd_flags & BD_F_MCE_BIT) == 0 ) {	printf("--- hey, leave_MCE: MCE bit was not set!\n");	return;    }    AD_WAIT_INIT(d, 1000);    flags = spltty();    d->bd_flags &= ~BD_F_MCE_BIT;    prev = inb(io_Index_Addr(d));    prev &= ~IA_TRD ;    outb(io_Index_Addr(d), prev & ~IA_MCE ); /* Clear the MCE bit */    wait_for_calibration(d);    splx(flags);}/* * only one source can be set... */static intmss_set_recsrc(snddev_info *d, int mask){    u_char   recdev;    mask &= d->mix_rec_devs;    switch (mask) {    case SOUND_MASK_LINE:    case SOUND_MASK_LINE3:	recdev = 0;	break;    case SOUND_MASK_CD:    case SOUND_MASK_LINE1:	recdev = 0x40;	break;    case SOUND_MASK_IMIX:	recdev = 0xc0;	break;    case SOUND_MASK_MIC:    default:	mask = SOUND_MASK_MIC;	recdev = 0x80;    }    ad_write(d, 0, (ad_read(d, 0) & 0x3f) | recdev);    ad_write(d, 1, (ad_read(d, 1) & 0x3f) | recdev);    d->mix_recsrc = mask;    return 0;}/* * mixer conversion table: from 0..100 scale to codec values * * I don't understand what's this for... maybe achieve a log-scale * volume control ? */static char mix_cvt[101] = {      0, 1, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,    43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,    65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,    80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,    91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99,     100}; /* * there are differences in the mixer depending on the actual sound * card. */static intmss_mixer_set(snddev_info *d, int dev, int value){    int             left = value & 0x000000ff;    int             right = (value & 0x0000ff00) >> 8;    int             regoffs;    mixer_tab *mix_d = &mix_devices;    u_char  old, val;    if (dev > 31)	return EINVAL;    if (!(d->mix_devs & (1 << dev)))	return EINVAL;    if (d->bd_id == MD_OPTI931)	mix_d = &(opti931_devices);    if ((*mix_d)[dev][LEFT_CHN].nbits == 0) {	DEB(printf("nbits = 0 for dev %d\n", dev) );	return EINVAL;    }    if (left > 100)	left = 100;    if (right > 100)	right = 100;    if ( (*mix_d)[dev][RIGHT_CHN].nbits == 0)	/* Mono control */	right = left;    d->mix_levels[dev] = left | (right << 8);#if 0    /* Scale volumes */    left = mix_cvt[left];    right = mix_cvt[right];#endif    /*     * Set the left channel     */    regoffs = (*mix_d)[dev][LEFT_CHN].regno;    old = val = ad_read(d, regoffs);    /*     * if volume is 0, mute chan. Otherwise, unmute.     */    if (regoffs != 0)  /* main input is different */	val = (left == 0 ) ? old | 0x80 : old & 0x7f ;    change_bits(mix_d, &val, dev, LEFT_CHN, left);    ad_write(d, regoffs, val);    DEB(printf("LEFT: dev %d reg %d old 0x%02x new 0x%02x\n",	dev, regoffs, old, val));    if ((*mix_d)[dev][RIGHT_CHN].nbits != 0) { /* have stereo */	/*	 * Set the right channel	 */	regoffs = (*mix_d)[dev][RIGHT_CHN].regno;	old = val = ad_read(d, regoffs);	if (regoffs != 1)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -