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>
