Date: Sat, 11 Oct 1997 18:51:50 -0400 From: john@jwlab.feith.com (John Wehle) To: multimedia@freebsd.org Subject: Patch to FreeBSD 3.0 AD1848 device driver Message-ID: <199710112251.SAA18270@jwlab.FEITH.COM>
next in thread | raw e-mail | index | archive | help
The enclosed patch clears up some of the snaps in the audio produced by the AD1848 which were caused by overuse of the autocalibration feature. The changes are based on the Analog Devices AD1845 datasheet and Ensoniq sample code. FYI: the AD1845 is pin compatible with the AD1846, AD1848, CS4231, and CS4248. Changes: 1) ad1848_output_block and ad1848_start_input activated autocalibration (which causes a snap) even though according to the documentation it's only necessary to do this once and it had already been performed by ad1848_init. 2) ad1848_prepare_for_IO suffered from code duplication seemingly due to someone trying to reconcile the code with similar code from another port. 3) ad1848_prepare_for_IO didn't ensure that the ACAL bit was cleared prior to disabling the MCE bit. This could cause an autocalibration to occur. 4) ad1848_halt suffered from code duplication seemingly due to someone trying to reconcile the code with similar code from another port. 5) ad1848_halt enabled MCE which according to the documentation it isn't necessary to do when disabling DMA, clearing the DMA registers, and clearing the INT bit. 6) The comment in ad1848_init didn't state that clearing the MCE bit causes an autocalibration since the ACAL bit was set with the indirect registers were loaded. Note: 1) The datasheet states the following about changing sample rates: "... Reads will produce "1000 0000 (80h)" until the resynchronization is complete. Poll the Index Register until something other than this value is returned." Sincerely, John Wehle ------------------8<------------------------8<------------------------ *** sys/i386/isa/sound/ad1848.c.ORIGINAL Tue Nov 12 20:59:56 1996 --- sys/i386/isa/sound/ad1848.c Sat Oct 11 15:06:45 1997 *************** *** 813,827 **** ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); ! ad_write (devc, 9, 0x0d); /* * Playback enable, single DMA channel mode, ! * auto calibration on. */ ! ad_leave_MCE (devc); /* ! * Starts the calibration process and ! * enters playback mode after it. ! */ ad_unmute (devc); devc->xfer_count = cnt; --- 813,825 ---- ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); ! ad_write (devc, 9, 0x05); /* * Playback enable, single DMA channel mode, ! * auto calibration off. */ ! ad_leave_MCE (devc); ! ad_unmute (devc); devc->xfer_count = cnt; *************** *** 877,891 **** ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff)); ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff)); ! ad_write (devc, 9, 0x0e); /* * Capture enable, single DMA channel mode, ! * auto calibration on. */ ! ad_leave_MCE (devc); /* ! * Starts the calibration process and ! * enters playback mode after it. ! */ ad_unmute (devc); devc->xfer_count = cnt; --- 875,887 ---- ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff)); ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff)); ! ad_write (devc, 9, 0x06); /* * Capture enable, single DMA channel mode, ! * auto calibration off. */ ! ad_leave_MCE (devc); ! ad_unmute (devc); devc->xfer_count = cnt; *************** *** 906,975 **** DISABLE_INTR (flags); ad_enter_MCE (devc); /* Enables changes to the format select reg */ fs = devc->speed_bits | (devc->format_bits << 5); if (devc->channels > 1) fs |= 0x10; ad_write (devc, 8, fs); /* * Write to I8 starts resyncronization. Wait until it completes. */ timeout = 10000; - #ifdef PC98 - while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80) - #else while (timeout > 0 && INB (devc->base) == 0x80) - #endif timeout--; - #ifdef PC98 - ad_write (devc, 8, fs); /* ! * Write to I8 starts resyncronization. Wait until it completes. */ - timeout = 10000; - while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80) - timeout--; - #endif - /* - * If mode == 2 (CS4231), set I28 also. It's the capture format register. - */ if (devc->mode == 2) { ! ad_write (devc, 28, fs); /* ! * Write to I28 starts resyncronization. Wait until it completes. */ timeout = 10000; - #ifdef PC98 - while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80) - #else while (timeout > 0 && INB (devc->base) == 0x80) - #endif timeout--; - } ! #ifdef PC98 ! ad_write (devc, 28, fs); ! /* ! * Write to I28 starts resyncronization. Wait until it completes. ! */ ! timeout = 10000; ! while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80) ! timeout--; ! #endif ! ! ad_leave_MCE (devc); /* ! * Starts the calibration process and ! * enters playback mode after it. ! */ RESTORE_INTR (flags); devc->xfer_count = 0; return 0; } --- 902,947 ---- DISABLE_INTR (flags); ad_enter_MCE (devc); /* Enables changes to the format select reg */ + fs = devc->speed_bits | (devc->format_bits << 5); if (devc->channels > 1) fs |= 0x10; ad_write (devc, 8, fs); + /* * Write to I8 starts resyncronization. Wait until it completes. */ + timeout = 10000; while (timeout > 0 && INB (devc->base) == 0x80) timeout--; /* ! * If mode == 2 (CS4231), set I28 also. It's the capture format register. */ if (devc->mode == 2) { ! ad_write (devc, 28, fs & 0x70); /* ! * Write to I28 starts resyncronization. Wait until it completes. */ + timeout = 10000; while (timeout > 0 && INB (devc->base) == 0x80) timeout--; } ! ad_write (devc, 9, ad_read (devc, 9) & 0xc7); ! ad_leave_MCE (devc); RESTORE_INTR (flags); + devc->xfer_count = 0; + return 0; } *************** *** 985,1000 **** ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad_mute (devc); - #ifdef PC98 - ad_enter_MCE (devc); - #endif - ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ - #ifdef PC98 - ad_leave_MCE (devc); - #endif - OUTB (0, io_Status (devc)); /* Clear interrupt status */ ! ad_enter_MCE (devc); OUTB (0, io_Status (devc)); /* Clear interrupt status */ ad_write (devc, 15, 0); /* Clear DMA counter */ ad_write (devc, 14, 0); /* Clear DMA counter */ --- 957,965 ---- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad_mute (devc); ! ad_write (devc, 9, ad_read (devc, 9) & 0xcc); /* Stop DMA */ ! OUTB (0, io_Status (devc)); /* Clear interrupt status */ ad_write (devc, 15, 0); /* Clear DMA counter */ ad_write (devc, 14, 0); /* Clear DMA counter */ *************** *** 1005,1016 **** ad_write (devc, 31, 0); /* Clear DMA counter */ } - ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ - - OUTB (0, io_Status (devc)); /* Clear interrupt status */ - OUTB (0, io_Status (devc)); /* Clear interrupt status */ - ad_leave_MCE (devc); - DMAbuf_reset_dma (dev); } --- 970,975 ---- *************** *** 1257,1263 **** nr_ad1848_devs++; /* ! * Toggle the MCE bit. It completes the initialization phase. */ ad_enter_MCE (devc); /* In case the bit was off */ --- 1216,1224 ---- nr_ad1848_devs++; /* ! * Toggle the MCE bit. This will cause an autocalibration ! * (since the ACAL bit was set earlier) and completes the ! * initialization phase. */ ad_enter_MCE (devc); /* In case the bit was off */ ------------------------------------------------------------------------- | Feith Systems | Voice: 1-215-646-8000 | Email: john@feith.com | | John Wehle | Fax: 1-215-540-5495 | | -------------------------------------------------------------------------
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199710112251.SAA18270>