home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / audiopdd.zip / chipset.c < prev    next >
C/C++ Source or Header  |  1999-02-27  |  13KB  |  521 lines

  1. //
  2. // chipset.c
  3. // 4-Feb-99
  4. //
  5. // 27-Feb-99: to use type-F DMA:
  6. //            pin control reg (i10): DTM (bit2) set to 1
  7. //            also, use DEMAND mode for dma channel, rather than single mode
  8. //
  9. // UCHAR  chipsetGET(USHORT type, USHORT reg);
  10. // VOID   chipsetSet(USHORT type, USHORT reg, UCHAR data);
  11. // VOID   chipsetMCE(USHORT mode);
  12. // USHORT chipsetSetDTM(USHORT dtm);
  13. // USHORT chipsetInit(USHORT bp, USHORT cp, USHORT mode, USHORT make);
  14. // USHORT chipsetIntPending(USHORT type);
  15. // USHORT chipsetIntReset(USHORT type);
  16. // UCHAR  chipsetWaitInit(VOID);
  17. // UCHAR  chipsetWaitACI(VOID);
  18.  
  19. #include "cs40.h"
  20.  
  21. // local protos
  22.  
  23. static UCHAR iGET(USHORT reg);
  24. static VOID  iSet(USHORT reg, UCHAR data);
  25. static UCHAR xGET(USHORT reg);
  26. static VOID  xSet(USHORT reg, UCHAR data);
  27. static UCHAR ciGET(USHORT reg);
  28. static VOID  ciSet(USHORT reg, UCHAR data);
  29.  
  30. // local data
  31.  
  32. static UCHAR  chipMake = 0;     // 0=CS, 0x100=Yamaha, 0x101=3DXG
  33. static UCHAR  chipVer = 0;      // 715,4231; 4232(4236non-B); 4235,4236,4237,4238,4239
  34. static USHORT chipMode = 0;     // 2 or 3
  35.  
  36. static USHORT basePort = 0;     // codec base (WSS base+4, though WSS used only in old WSS lingo)
  37. static USHORT dataPort = 0;     // data (basePort+1)
  38. static USHORT statusPort = 0;   // status (basePort+2)
  39.  
  40. static USHORT controlPort= 0;   // control port
  41. static USHORT cindexPort = 0;   // control index port
  42. static USHORT cdataPort = 0;    // control data port
  43.  
  44.  
  45. // ---------------------
  46. // in: index reg to read
  47. //out: data at reg
  48. //nts: get index-indirect reg
  49. //     compiler is typically more efficent when using dataPort instead of basePort+1
  50.  
  51. static UCHAR iGET(USHORT reg) {
  52.  
  53.  UCHAR data;
  54.  UCHAR mt;              // MCE and TRD bits
  55.  
  56.  _cli_();
  57.  mt = inp(basePort) & 0x60;
  58.  outp(basePort,mt|reg);
  59.  data = inp(dataPort);
  60.  _sti_();
  61.  
  62.  return data;
  63. }
  64.  
  65.  
  66. // ----------------------
  67. // in: index reg to write
  68. //     data to write
  69. //out: n/a
  70. //nts: set index-indirect reg
  71.  
  72. static VOID iSet(USHORT reg, UCHAR data) {
  73.  
  74.  UCHAR mt;              // MCE and TRD bits
  75.  
  76.  _cli_();
  77.  mt = inp(basePort) & 0x60;
  78.  outp(basePort,mt|reg);
  79.  outp(dataPort,data);
  80.  _sti_();
  81.  
  82.  return;
  83. }
  84.  
  85.  
  86. // -----------------------
  87. // in: x-index reg to read
  88. //out: data at reg
  89. //nts: get extended reg
  90. //     requires mode3
  91. //     ; d7   d6   d5   d4   d3    d2  d1  d0
  92. //     ;XA3  XA2  XA1  XA0  XRAE  XA4 rez  ACF
  93. //     ACF is not in 4235/9 anymore (for ADPCM capture freeze)
  94.  
  95. static UCHAR xGET(USHORT reg) {
  96.  
  97.  USHORT tReg;
  98.  UCHAR data;
  99.  UCHAR mt;              // MCE and TRD bits
  100.  
  101.  tReg = (reg >> 2) & 4; // XA4 to d2 (only want d2 bit)
  102.  reg = reg << 4;        // XA3-0 to d7-4 (d3-0 cleared by this)
  103.  reg = reg|0x10|tReg;   // set XRAE, and merge d7-d4,d2
  104.  
  105.  _cli_();
  106.  mt = inp(basePort) & 0x60;
  107.  outp(basePort,mt|23);  // select I23, extended reg access (and ACF bit) (R1 is now x-addr reg)
  108.  data = inp(dataPort);  // read first to get ACF
  109.  reg = reg|(data & 1);  // x-reg address data
  110.  outp(dataPort,reg);    // after this write, R1 is now x-data reg
  111.  data = inp(dataPort);  // read data of x-reg
  112.  _sti_();
  113.  
  114.  return data;
  115. }
  116.  
  117.  
  118. // ------------------------
  119. // in: x-index reg to write
  120. //     data to write
  121. //out: n/a
  122. //nts: set extended reg
  123. //     requires mode3
  124. //     ; d7   d6   d5   d4   d3    d2  d1  d0
  125. //     ;XA3  XA2  XA1  XA0  XRAE  XA4 rez  ACF
  126.  
  127. static VOID xSet(USHORT reg, UCHAR data) {
  128.  
  129.  USHORT tReg;
  130.  UCHAR tData;
  131.  UCHAR mt;              // MCE and TRD bits
  132.  
  133.  tReg = (reg >> 2) & 4; // XA4 to d2 (only want d2 bit)
  134.  reg = reg << 4;        // XA3-0 to d7-4 (d3-0 cleared by this)
  135.  reg = reg|0x10|tReg;   // set XRAE, and merge d7-d4,d2
  136.  
  137.  _cli_();
  138.  mt = inp(basePort) & 0x60;
  139.  outp(basePort,mt|23);  // select I23, extended reg access (and ACF bit) (R1 is now x-addr reg)
  140.  tData = inp(dataPort); // read first to get ACF
  141.  reg = reg|(tData & 1); // x-reg address data
  142.  outp(dataPort,reg);    // after this write, R1 is now x-data reg
  143.  outp(dataPort,data);   // write data to x-reg
  144.  _sti_();
  145.  
  146.  return;
  147. }
  148.  
  149.  
  150. // -----------------------------
  151. // in: control index reg to read
  152. //out: data at reg
  153. //nts: get index-indirect control reg
  154.  
  155. static UCHAR ciGET(USHORT reg) {
  156.  
  157.  UCHAR data;
  158.  
  159.  _cli_();
  160.  outp(cindexPort,reg);
  161.  data = inp(cdataPort);
  162.  _sti_();
  163.  
  164.  return data;
  165. }
  166.  
  167.  
  168. // ------------------------------
  169. // in: control index reg to write
  170. //out: n/a
  171. //nts: set index-indirect control reg
  172.  
  173. static VOID ciSet(USHORT reg, UCHAR data) {
  174.  
  175.  _cli_();
  176.  outp(cindexPort,reg);
  177.  outp(cdataPort, data);
  178.  _sti_();
  179.  
  180.  return;
  181. }
  182.  
  183.  
  184. // -------------------------------------------------------------------------------
  185. // in: type ='i' for index
  186. //           'x' for extended
  187. //           'c' for index-control
  188. //           'C' for direct control
  189. //           'd' for direct (not usually used)
  190. //     reg to read
  191. //out: reg data
  192. //nts: for 's' use chipsetStatus(READ_STATUS)
  193. //     'C' (direct control access) is not used by 715
  194.  
  195. UCHAR chipsetGET(USHORT type, USHORT reg) {
  196.  
  197.  UCHAR data = 0xFF;
  198.  
  199.  if (type == 'i') {
  200.     data = iGET(reg);
  201.  }
  202.  else if (type == 'x') {
  203.     data = xGET(reg);
  204.  }
  205.  else if (type == 'c') {
  206.     data = ciGET(reg);
  207.  }
  208.  else if (type == 'C') {
  209.     data = inp(controlPort+reg);
  210.  }
  211.  else if (type == 'd') {
  212.     data = inp(basePort+reg);  // typically not used (specific chipsetGETInit() used instead)
  213.  }
  214.  
  215.  return data;
  216. }
  217.  
  218.  
  219. // -------------------------------------------------------------------------------
  220. // in: type ='i' for index
  221. //           'x' for extended
  222. //           'c' for index-control
  223. //           'C' for direct control
  224. //           'd' for direct (not usually used)
  225. //     reg to write
  226. //     data to write
  227. //out: n/a
  228. //nts: for 's' use chipsetStatus(RESET_STATUS)
  229. //     'C' (direct control access) is not used by 715
  230.  
  231. VOID chipsetSet(USHORT type, USHORT reg, UCHAR data) {
  232.  
  233.  if (type == 'i') {
  234.     iSet(reg,data);
  235.  }
  236.  else if (type == 'x') {
  237.     xSet(reg,data);
  238.  }
  239.  else if (type == 'c') {
  240.     ciSet(reg,data);
  241.  }
  242.  else if (type == 'C') {
  243.     outp(controlPort+reg,data);
  244.  }
  245.  else if (type == 'd') {
  246.     outp(basePort+reg,data);    // typically not used
  247.  }
  248.  
  249.  return;
  250. }
  251.  
  252.  
  253. // -------------------------------------
  254. // in: state to set dtm (1=DTM, 0=no DTM)
  255. //out: previous state (1 or 0)
  256. //nts:
  257.  
  258. USHORT chipsetSetDTM(USHORT dtmFlag) {
  259.  
  260.  USHORT lastState;
  261.  UCHAR data;
  262.  
  263.  data = (chipsetGET('i', PIN_CONTROL_REG));
  264.  lastState = (data & 4) != 0;
  265.  
  266.  if (lastState != dtmFlag) {
  267.     data = data & ~4;
  268.     if (dtmFlag) data = data | 4;
  269.     chipsetSet('i', PIN_CONTROL_REG, data);
  270.  }
  271.  
  272.  return lastState;
  273. }
  274.  
  275.  
  276. // -------------------------------------
  277. // in: bp = base port
  278. //     cp = control port (can be 0)
  279. //     mode = mode (2, 3 also for cs)
  280. //     make = chip make (0=CS, 0x100=Yamaha, 0x101=3DXG)
  281. //out:
  282. //nts:
  283.  
  284. USHORT chipsetInit(USHORT bp, USHORT cp, USHORT mode, USHORT make) {
  285.  
  286.  USHORT rc = 0;
  287.  UCHAR data;
  288.  
  289.  if ((bp < 0x100) || (cp && (cp < 0x100)) || (mode < 2) || (mode > 2)) {
  290.     rc = 1;
  291.     goto ExitNow;
  292.  }
  293.  
  294.  basePort   = bp;
  295.  dataPort   = bp+1;
  296.  statusPort = bp+2;
  297.  controlPort= cp;
  298.  
  299.  chipMake = make;
  300.  chipVer = 0;   // ref it for now
  301.  
  302.  if (cp) {
  303.     if (make & 0x100) {
  304.        cindexPort = cp;       // 715
  305.        cdataPort = cp+1;
  306.     }
  307.     else {
  308.        cindexPort = cp+3;     // CS
  309.        cdataPort = cp+4;
  310.     }
  311.  }
  312.  chipMode = mode;
  313.  
  314.  rc = chipsetWaitInit();
  315.  if (rc) {
  316. ddprintf("1:chipsetWaitInit()=%u\n",rc);
  317.     goto ExitNow;
  318.  }
  319.  
  320.  chipsetSet('i', MODE_AND_ID_REG, 0x40);        // set mode 2
  321.  
  322.  data = chipsetGET('i',INTERFACE_CONFIG_REG);
  323.  data = data & 0xDC;                            // disable PEN/CEN
  324.  chipsetSet('i', INTERFACE_CONFIG_REG, data);
  325.  
  326.  chipsetSet('i', LEFT_OUTPUT_CONTROL, 0x8F);    // output mute and down
  327.  chipsetSet('i', RIGHT_OUTPUT_CONTROL, 0x8F);
  328.  
  329.  chipsetSet('i', MONO_IO_CONTROL, 0xCF);        // mom mute and down
  330.  chipsetSet('i', LOOPBACK_CONTROL_REG, 0xFC);   // monitor mute and down
  331.  
  332.  chipsetSet('i', LEFT_DAC_OUTPUT_CONTROL, 0xBF); // DAC output mute and down
  333.  chipsetSet('i', RIGHT_DAC_OUTPUT_CONTROL, 0xBF);
  334.  
  335.  chipsetMCE(1);
  336.  
  337.  // full calibration uses bits 4/3, available in 4232+ (incl.4235/9)
  338.  // difference between full and just convertor (4231, and org source) is
  339.  // the analog mixer is not calibrated -- see the benefits of each calibration
  340.  // mode type in the docs (CS4232, p.53 talks about why might want to use no calibration)
  341.  // note that a full calibration is always done at power-up, and this is the init code...
  342.  
  343.  data = chipsetGET('i', INTERFACE_CONFIG_REG) | 0x18; // full calibration
  344.  chipsetSet('i', INTERFACE_CONFIG_REG, data);
  345.  
  346.  chipsetMCE(0);
  347.  
  348.  rc = chipsetWaitInit();                // yes, have to wait on INIT bit after calibrate (by spec)
  349.  if (rc) {
  350. ddprintf("2:chipsetWaitInit()=%u\n",rc);
  351.     goto ExitNow;
  352.  }
  353.  
  354.  rc = chipsetWaitACI();
  355.  if (rc) {
  356. ddprintf("chipsetWaitACI()=%u\n",rc);
  357.     goto ExitNow;
  358.  }
  359.  
  360.  // playback/capture mode change enables off (PMCE/CMCE, not for 4231 but yes 715),
  361.  // also timer feature disable
  362.  
  363.  chipsetSet('i', ALT_FEATURE_ENABLE_1, 0);      
  364.  
  365.  // mute and down inputs to 0 dB gain
  366.  
  367.  chipsetSet('i', LEFT_AUX1_INPUT_CONTROL,  0x88);
  368.  chipsetSet('i', RIGHT_AUX1_INPUT_CONTROL, 0x88);
  369.  chipsetSet('i', LEFT_AUX2_INPUT_CONTROL,  0x88);
  370.  chipsetSet('i', RIGHT_AUX2_INPUT_CONTROL, 0x88);
  371.  chipsetSet('i', LEFT_LINE_INPUT_CONTROL,  0x88);
  372.  chipsetSet('i', RIGHT_LINE_INPUT_CONTROL, 0x88);
  373.  
  374.  // tropez code did the monitor and DAC output controls AGAIN... I don't
  375.  
  376.  outp(statusPort,0);    // clear all int flags before enabling interrupt pin (done next)
  377.  
  378.  // enable interrupts (better not get spurious ints since handler won't own IRQ until start)
  379.  
  380.  data = 2 | (chipsetGET('i', PIN_CONTROL_REG) & ~3);
  381.  chipsetSet('i', PIN_CONTROL_REG, data);
  382.  
  383. ExitNow:
  384.  return rc;
  385. }
  386.  
  387.  
  388. // -------------------------------------
  389. // in: INT type to check
  390. //out: 0=not pending, 1=pending
  391. //nts:
  392.  
  393. USHORT chipsetIntPending(USHORT type) {
  394.  
  395.  UCHAR data = chipsetGET('i',ALT_FEATURE_STATUS);
  396.  
  397.  switch(type) {
  398.  case AUDIOHW_WAVE_PLAY:
  399.     data = data & PLAY_INTERRUPT;
  400.     break;
  401.  case AUDIOHW_WAVE_CAPTURE:
  402.     data = data & CAPTURE_INTERRUPT;
  403.     break;
  404.  case AUDIOHW_TIMER:
  405.     data = data & TIMER_INTERRUPT;
  406.     break;
  407.  case -1:
  408.     data = data & ALL_INTERRUPTS;
  409.     break;
  410.  default:
  411.     data = 0;
  412.  }
  413.  
  414.  return (data != 0);
  415. }
  416.  
  417.  
  418. // -------------------------------------
  419. // in: INT type to clear
  420. //out: n/a
  421. //nts:
  422.  
  423. VOID chipsetIntReset(USHORT type) {
  424.  
  425.  UCHAR data = 0;
  426.  
  427.  switch(type) {
  428.  case AUDIOHW_WAVE_PLAY:
  429.     data = CLEAR_PI;
  430.     break;
  431.  case AUDIOHW_WAVE_CAPTURE:
  432.     data = CLEAR_CI;
  433.     break;
  434.  case AUDIOHW_TIMER:
  435.     data = CLEAR_TI;
  436.     break;
  437.  }
  438.  
  439.  if (data) chipsetSet('i',ALT_FEATURE_STATUS,data);
  440.  
  441.  return;
  442. }
  443.  
  444.  
  445. // -------------------------------------
  446. // in: n/a
  447. //out: 0=okay, else timeout error
  448. //nts: wait for INIT bit to clear
  449. //     tropez code first looked/waited for INIT bit to go from 0 -> 1, which seems pointless
  450. //     and not well supported for doing it, so I don't (it also read it once more before returning)
  451. //
  452. //     had this timeout at first use once (twice actually) but went away after power cycle
  453. //     may have been a messed up config since it was during initial testing (which I'm still
  454. //     doing -- 7-Feb-99 00:51 -- maybe the DMA isn't running, will be checking right after this)
  455. //
  456. //     above (timeout) was likely related to the fact tat I was using dataPort instead of basePort!
  457. //     ... still checking out no sound problem (might be this?)
  458.  
  459. UCHAR chipsetWaitInit(VOID) {
  460.  
  461.  USHORT cnt = 0;
  462.  UCHAR  data = inp(basePort);
  463.  
  464.  while (data & 0x80) {
  465.     iodelay(WAIT_1US);
  466.     data = inp(basePort);
  467.     cnt++;
  468.     if (cnt == 65535) break;  // 65.5 millseconds is way too long, timeout
  469.  }
  470.  
  471.  return (data & 0x80); // just return bit7
  472. }
  473.  
  474.  
  475. // -------------------------------------
  476. // in: n/a
  477. //out: 0=okay, else timeout error
  478. //nts: wait for ACI bit to clear (auto-calibration)
  479. //     full calibration can take 450 sample periods:
  480. //     - at 44.1kHz that's 450/44100=10.2 milliseconds (4235+ always run internally at 44.1kHz)
  481. //     - at  5.5kHz that's 450/5512 =81.6 milliseconds
  482. //     since quite long, using WAIT_1MS (1 ms) wait rather than lots of WAIT_1US (1 us)
  483.  
  484. UCHAR chipsetWaitACI(VOID) {
  485.  
  486.  USHORT cnt = 0;
  487.  UCHAR  data = iGET(ERROR_STATUS_INIT_REG);  // i11
  488.  
  489.  while (data & ACI_BIT) {
  490.     iodelay(WAIT_1MS);
  491.     data = iGET(ERROR_STATUS_INIT_REG);
  492.     cnt++;
  493.     if (cnt > 162) break;  // 81.64 milliseconds is longest is should ever be, timeout if longer
  494.  }                         // using double since WAIT_1MS is 2000 loops, which may be off a bit
  495.  
  496.  return (data & ACI_BIT);  // just return bit5
  497. }
  498.  
  499.  
  500. // -------------------------------------
  501. // in: mode 0=off, else on
  502. //out:
  503. //nts:
  504.  
  505. VOID chipsetMCE(USHORT mode) {
  506.  
  507.  UCHAR data;
  508.  
  509.  data = inp(basePort);
  510.  if (mode) {
  511.     data = data | MCE_ON;
  512.  }
  513.  else {
  514.     data = data & MCE_OFF;
  515.  }
  516.  outp(basePort, data);
  517.  
  518.  return;
  519. }
  520.  
  521.