home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 June B / Pcwk6b98.iso / Mpeg3 / Dos / MP3 / MPG12304.EXE / MDMA.C < prev    next >
C/C++ Source or Header  |  1997-05-06  |  14KB  |  516 lines

  1. /*
  2.  
  3. Name:
  4. MDMA.C
  5.  
  6. Description:
  7. DMA routines
  8.  
  9. Portability:
  10.  
  11. MSDOS:    BC(y)    Watcom(y)    DJGPP(y)
  12. Win95:    n
  13. Os2:    n
  14. Linux:    n
  15.  
  16. (y) - yes
  17. (n) - no (not possible or not useful)
  18. (?) - may be possible, but not tested
  19.  
  20. */
  21. #include <dos.h>
  22. #include <malloc.h>
  23. #include <conio.h>
  24. #include "mdma.h"
  25.  
  26.  
  27. /* DMA Controler #1 (8-bit controller) */
  28. #define DMA1_STAT       0x08            /* read status register */
  29. #define DMA1_WCMD       0x08            /* write command register */
  30. #define DMA1_WREQ       0x09            /* write request register */
  31. #define DMA1_SNGL       0x0A            /* write single bit register */
  32. #define DMA1_MODE       0x0B            /* write mode register */
  33. #define DMA1_CLRFF      0x0C            /* clear byte ptr flip/flop */
  34. #define DMA1_MCLR       0x0D            /* master clear register */
  35. #define DMA1_CLRM       0x0E            /* clear mask register */
  36. #define DMA1_WRTALL     0x0F            /* write all mask register */
  37.  
  38. /* DMA Controler #2 (16-bit controller) */
  39. #define DMA2_STAT       0xD0            /* read status register */
  40. #define DMA2_WCMD       0xD0            /* write command register */
  41. #define DMA2_WREQ       0xD2            /* write request register */
  42. #define DMA2_SNGL       0xD4            /* write single bit register */
  43. #define DMA2_MODE       0xD6            /* write mode register */
  44. #define DMA2_CLRFF      0xD8            /* clear byte ptr flip/flop */
  45. #define DMA2_MCLR       0xDA            /* master clear register */
  46. #define DMA2_CLRM       0xDC            /* clear mask register */
  47. #define DMA2_WRTALL     0xDE            /* write all mask register */
  48.  
  49. #define DMA0_ADDR       0x00            /* chan 0 base adddress */
  50. #define DMA0_CNT        0x01            /* chan 0 base count */
  51. #define DMA1_ADDR       0x02            /* chan 1 base adddress */
  52. #define DMA1_CNT        0x03            /* chan 1 base count */
  53. #define DMA2_ADDR       0x04            /* chan 2 base adddress */
  54. #define DMA2_CNT        0x05            /* chan 2 base count */
  55. #define DMA3_ADDR       0x06            /* chan 3 base adddress */
  56. #define DMA3_CNT        0x07            /* chan 3 base count */
  57. #define DMA4_ADDR       0xC0            /* chan 4 base adddress */
  58. #define DMA4_CNT        0xC2            /* chan 4 base count */
  59. #define DMA5_ADDR       0xC4            /* chan 5 base adddress */
  60. #define DMA5_CNT        0xC6            /* chan 5 base count */
  61. #define DMA6_ADDR       0xC8            /* chan 6 base adddress */
  62. #define DMA6_CNT        0xCA            /* chan 6 base count */
  63. #define DMA7_ADDR       0xCC            /* chan 7 base adddress */
  64. #define DMA7_CNT        0xCE            /* chan 7 base count */
  65.  
  66. #define DMA0_PAGE       0x87            /* chan 0 page register (refresh)*/
  67. #define DMA1_PAGE       0x83            /* chan 1 page register */
  68. #define DMA2_PAGE       0x81            /* chan 2 page register */
  69. #define DMA3_PAGE       0x82            /* chan 3 page register */
  70. #define DMA4_PAGE       0x8F            /* chan 4 page register (unuseable)*/
  71. #define DMA5_PAGE       0x8B            /* chan 5 page register */
  72. #define DMA6_PAGE       0x89            /* chan 6 page register */
  73. #define DMA7_PAGE       0x8A            /* chan 7 page register */
  74.  
  75. #define MAX_DMA         8
  76.  
  77. #define DMA_DECREMENT   0x20    /* mask to make DMA hardware go backwards */
  78.  
  79. typedef struct {
  80.     UBYTE dma_disable;      /* bits to disable dma channel */
  81.     UBYTE dma_enable;       /* bits to enable dma channel */
  82.     UWORD page;                     /* page port location */
  83.     UWORD addr;                     /* addr port location */
  84.     UWORD count;            /* count port location */
  85.     UWORD single;           /* single mode port location */
  86.     UWORD mode;                     /* mode port location */
  87.     UWORD clear_ff;         /* clear flip-flop port location */
  88.     UBYTE write;            /* bits for write transfer */
  89.     UBYTE read;                     /* bits for read transfer */
  90. } DMA_ENTRY;
  91.  
  92. /* Variables needed ... */
  93.  
  94. static DMA_ENTRY mydma[MAX_DMA] = {
  95.  
  96. /* DMA channel 0 */
  97.             {0x04,0x00,DMA0_PAGE,DMA0_ADDR,DMA0_CNT,
  98.              DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x48,0x44},
  99.  
  100. /* DMA channel 1 */
  101.             {0x05,0x01,DMA1_PAGE,DMA1_ADDR,DMA1_CNT,
  102.              DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x49,0x45},
  103.  
  104. /* DMA channel 2 */
  105.             {0x06,0x02,DMA2_PAGE,DMA2_ADDR,DMA2_CNT,
  106.              DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x4A,0x46},
  107.  
  108. /* DMA channel 3 */
  109.             {0x07,0x03,DMA3_PAGE,DMA3_ADDR,DMA3_CNT,
  110.              DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x4B,0x47},
  111.  
  112. /* DMA channel 4 */
  113.             {0x04,0x00,DMA4_PAGE,DMA4_ADDR,DMA4_CNT,
  114.              DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x48,0x44},
  115.  
  116. /* DMA channel 5 */
  117.             {0x05,0x01,DMA5_PAGE,DMA5_ADDR,DMA5_CNT,
  118.              DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x49,0x45},
  119.  
  120. /* DMA channel 6 */
  121.             {0x06,0x02,DMA6_PAGE,DMA6_ADDR,DMA6_CNT,
  122.              DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x4A,0x46},
  123.  
  124. /* DMA channel 7 */
  125.             {0x07,0x03,DMA7_PAGE,DMA7_ADDR,DMA7_CNT,
  126.              DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x4B,0x47},
  127. };
  128.  
  129.  
  130. /*
  131.  
  132. Each specialised DMA code part should provide the following things:
  133.  
  134. In MDMA.H:
  135.  
  136.   -    a DMAMEM typedef, which should contain all the data that the
  137.     routines need for maintaining/allocating/freeing dma memory.
  138.  
  139.  
  140. In MDMA.C:
  141.  
  142.   -    2 macros ENTER_CRITICAL and LEAVE_CRITICAL
  143.  
  144.   - A function 'static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)'
  145.     which should perform the actual dma-memory allocation. It should
  146.     use DMAMEM *dm to store all it's information.
  147.  
  148.   - A function 'static void MDma_FreeMem0(DMAMEM *dm)' to free the memory
  149.  
  150.   - A function 'static ULONG MDma_GetLinearPtr(DMAMEM *dm)' which should
  151.     return the linear 20 bits pointer to the actual dmabuffer.. this
  152.     function is    used by MDma_Start
  153.  
  154.   - A function 'void *MDma_GetPtr(DMAMEM *dm)' which should return a pointer
  155.     to the dmabuffer. If the dma memory can't be accessed directly it should
  156.     return a pointer to a FAKE dma buffer (DJGPP!!)
  157.  
  158.   - A function 'void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)'. This
  159.     function will be called each time a routine wrote something to the
  160.     dmabuffer (returned by MDma_GetPtr()). In the case of a FAKE dmabuffer
  161.     this routine should take care of copying the data from the fake buffer to
  162.     the real dma memory ('count' bytes from byteoffset 'index').
  163.  
  164. */
  165.  
  166.  
  167.  
  168. #ifdef __WATCOMC__
  169.  
  170. /****************************************************************************
  171. ********************* Watcom C specialised DMA code: ************************
  172. ****************************************************************************/
  173.  
  174. #define ENTER_CRITICAL IRQ_PUSH_OFF()
  175. extern void IRQ_PUSH_OFF (void);
  176. #pragma aux IRQ_PUSH_OFF =      \
  177.     "pushfd",                   \
  178.         "cli"           \
  179.                 modify [esp];
  180.  
  181. #define LEAVE_CRITICAL IRQ_POP()
  182. extern void IRQ_POP (void);
  183. #pragma aux IRQ_POP =   \
  184.         "popfd"         \
  185.                 modify [esp];
  186.  
  187.  
  188. static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)
  189. /*
  190.     Allocates a dma buffer of 'size' bytes.
  191.     returns FALSE if failed.
  192. */
  193. {
  194.     static union REGS r;
  195.     ULONG p;
  196.  
  197.     /* allocate TWICE the size of the requested dma buffer..
  198.     this fixes the 'page-crossing' bug of previous versions */
  199.  
  200.     r.x.eax = 0x0100;           /* DPMI allocate DOS memory */
  201.     r.x.ebx = ((size*2) + 15) >> 4; /* Number of paragraphs requested */
  202.  
  203.     int386 (0x31, &r, &r);
  204.  
  205.     if( r.x.cflag ) return 0;    /* failed */
  206.  
  207.     dm->raw_selector=r.x.edx;
  208.  
  209.     /* convert the segment into a linear address */
  210.  
  211.     p=(r.x.eax&0xffff)<<4;
  212.  
  213.     /* if the first half of the allocated memory crosses a page
  214.     boundary, return the second half which is then guaranteed to
  215.     be page-continuous */
  216.  
  217.   if( (p>>16) != ((p+size-1)>>16) ) p+=size;
  218.  
  219.         dm->continuous=(void *)p;
  220.  
  221.     return 1;
  222. }
  223.  
  224.  
  225. static void MDma_FreeMem0(DMAMEM *dm)
  226. {
  227.     static union REGS r;
  228.     r.x.eax = 0x0101;               /* DPMI free DOS memory */
  229.     r.x.edx = dm->raw_selector;     /* base selector */
  230.     int386 (0x31, &r, &r);
  231. }
  232.  
  233.  
  234. static ULONG MDma_GetLinearPtr(DMAMEM *dm)
  235. {
  236.     return (ULONG)dm->continuous;
  237. }
  238.  
  239.  
  240. void *MDma_GetPtr(DMAMEM *dm)
  241. {
  242.     return(dm->continuous);
  243. }
  244.  
  245.  
  246. void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)
  247. {
  248.     /* This function doesnt do anything here (WATCOM C
  249.        can access dma memory directly) */
  250. }
  251.  
  252.  
  253. #elif defined(__DJGPP__)
  254. /****************************************************************************
  255. *********************** DJGPP specialised DMA code: *************************
  256. ****************************************************************************/
  257. #define ENTER_CRITICAL __asm__( "pushf \n\t cli" )
  258. #define LEAVE_CRITICAL __asm__( "popf \n\t" )
  259. #include <sys/farptr.h>
  260.  
  261. static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)
  262. /*
  263.     Allocates a dma buffer of 'size' bytes - one in the code segment and
  264.         one in the lower 1 Mb physical mem.
  265.     It doesn't check if the dma mem is page-continuous, and can only be
  266.         used to allocate exactly 1 block.
  267. */
  268. {
  269.     dm->raw.size = (size + 15) >> 4;
  270.     if (_go32_dpmi_allocate_dos_memory(&(dm->raw)))
  271.       return 0;
  272.     dm->continuous = (void *) malloc(size);
  273.         return 1;
  274. }
  275.  
  276.  
  277.  
  278. static void MDma_FreeMem0(DMAMEM *dm)
  279. {
  280.     _go32_dpmi_free_dos_memory(&(dm->raw));
  281.     free(dm->continuous);
  282. }
  283.  
  284. static ULONG MDma_GetLinearPtr(DMAMEM *dm)
  285. {
  286.     return (ULONG) dm->raw.rm_segment << 4;
  287. }
  288.  
  289.  
  290. void *MDma_GetPtr(DMAMEM *dm)
  291. {
  292.     return(dm->continuous);
  293. }
  294.  
  295. void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)
  296. {
  297.    char *src = &(((UBYTE*)dm->continuous)[index]);
  298.    ULONG dest = 16 * dm->raw.rm_segment + (ULONG) index;
  299.    _farsetsel(_go32_conventional_mem_selector());
  300.    while(count--) {
  301.       _farnspokeb(dest++, *(src++));
  302.    }
  303. }
  304.  
  305. #else
  306.  
  307. /****************************************************************************
  308. ********************* Borland C specialised DMA code: ***********************
  309. ****************************************************************************/
  310.  
  311. #define ENTER_CRITICAL asm{ pushf; cli }
  312. #define LEAVE_CRITICAL asm{ popf }
  313.  
  314. #define LPTR(ptr) (((ULONG)FP_SEG(ptr)<<4)+FP_OFF(ptr))
  315. #define NPTR(ptr) MK_FP(FP_SEG(p)+(FP_OFF(p)>>4),FP_OFF(p)&15)
  316.  
  317.  
  318. static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)
  319. /*
  320.     Allocates a dma buffer of 'size' bytes.
  321.     returns FALSE if failed.
  322. */
  323. {
  324.     char huge *p;
  325.     ULONG s;
  326.  
  327.     /* allocate TWICE the size of the requested dma buffer..
  328.     so we can always get a page-contiguous dma buffer */
  329.  
  330.     if((dm->raw=malloc((ULONG)size*2))==NULL) return 0;
  331.  
  332.     p=(char huge *)dm->raw;
  333.     s=LPTR(p);
  334.  
  335.     /* if the first half of the allocated memory crosses a page
  336.     boundary, return the second half which is then guaranteed to
  337.     be page-continuous */
  338.  
  339.     if( (s>>16) != ((s+size-1)>>16) ) p+=size;
  340.  
  341.     /* put the page-continuous pointer into DMAMEM */
  342.  
  343.     dm->continuous=NPTR(p);
  344.  
  345.     return 1;
  346. }
  347.  
  348.  
  349. static void MDma_FreeMem0(DMAMEM *dm)
  350. {
  351.     free(dm->raw);
  352. }
  353.  
  354.  
  355. static ULONG MDma_GetLinearPtr(DMAMEM *dm)
  356. {
  357.     return LPTR(dm->continuous);
  358. }
  359.  
  360.  
  361. void *MDma_GetPtr(DMAMEM *dm)
  362. {
  363.     return(dm->continuous);
  364. }
  365.  
  366. #pragma argsused
  367.  
  368. void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)
  369. {
  370.     /* This function doesnt do anything here (BORLAND C
  371.        can access dma memory directly) */
  372. }
  373.  
  374. #endif
  375.  
  376.  
  377. /****************************************************************************
  378. ************************* General DMA code: *********************************
  379. ****************************************************************************/
  380.  
  381.  
  382. DMAMEM *MDma_AllocMem(UWORD size)
  383. {
  384.     DMAMEM *p;
  385.  
  386.     /* allocate dma memory structure */
  387.  
  388.     if(!(p=(DMAMEM *)malloc(sizeof(DMAMEM)))) return NULL;
  389.  
  390.     /* allocate dma memory */
  391.  
  392.     if(!MDma_AllocMem0(p,size)){
  393.  
  394.         /* didn't succeed? -> free everything & return NULL */
  395.  
  396.         free(p);
  397.         return NULL;
  398.     }
  399.  
  400.     return p;
  401. }
  402.  
  403.  
  404. void MDma_FreeMem(DMAMEM *p)
  405. {
  406.     MDma_FreeMem0(p);
  407.     free(p);
  408. }
  409.  
  410.  
  411. int MDma_Start(int channel,DMAMEM *dm,UWORD size,int type)
  412. {
  413.     DMA_ENTRY *tdma;
  414.     ULONG s_20bit,e_20bit;
  415.     UWORD spage,saddr,tcount;
  416.     UWORD epage,eaddr;
  417.     UBYTE cur_mode;
  418.  
  419.     tdma=&mydma[channel];           /* point to this dma data */
  420.  
  421.     /* Convert the pc address to a 20 bit physical
  422.        address that the DMA controller needs */
  423.  
  424.     s_20bit = MDma_GetLinearPtr(dm);
  425.  
  426.     e_20bit = s_20bit + size - 1;
  427.     spage = s_20bit>>16;
  428.     epage = e_20bit>>16;
  429.  
  430.     if(spage != epage) return 0;
  431.  
  432.     if(channel>=4){
  433.         /* if 16-bit xfer, then addr,count & size are divided by 2 */
  434.         s_20bit = s_20bit >> 1;
  435.         e_20bit = e_20bit >> 1;
  436.         size = size >> 1;
  437.     }
  438.  
  439.     saddr=s_20bit&0xffff;
  440.  
  441.     tcount = size-1;
  442.  
  443.     switch (type){
  444.  
  445.         case READ_DMA:
  446.             cur_mode = tdma->read;
  447.             break;
  448.  
  449.         case WRITE_DMA:
  450.             cur_mode = tdma->write;
  451.             break;
  452.  
  453.         case INDEF_READ:
  454.             cur_mode = tdma->read | 0x10;   /* turn on auto init */
  455.             break;
  456.  
  457.         case INDEF_WRITE:
  458.             cur_mode = tdma->write | 0x10;  /* turn on auto init */
  459.             break;
  460.     }
  461.  
  462.     ENTER_CRITICAL;
  463.     outportb(tdma->single,tdma->dma_disable);               /* disable channel */
  464.     outportb(tdma->mode,cur_mode);                                  /* set mode */
  465.     outportb(tdma->clear_ff,0);                                             /* clear f/f */
  466.     outportb(tdma->addr,saddr&0xff);                                /* LSB */
  467.     outportb(tdma->addr,saddr>>8);                                  /* MSB */
  468.     outportb(tdma->page,spage);                                             /* page # */
  469.     outportb(tdma->clear_ff,0);                                             /* clear f/f */
  470.     outportb(tdma->count,tcount&0x0ff);                             /* LSB count */
  471.     outportb(tdma->count,tcount>>8);                                /* MSB count */
  472.     outportb(tdma->single,tdma->dma_enable);                /* enable */
  473.     LEAVE_CRITICAL;
  474.  
  475.     return 1;
  476. }
  477.  
  478.  
  479. void MDma_Stop(int channel)
  480. {
  481.     DMA_ENTRY *tdma;
  482.     tdma=&mydma[channel];                        /* point to this dma data */
  483.     outportb(tdma->single,tdma->dma_disable);   /* disable chan */
  484. }
  485.  
  486.  
  487. UWORD MDma_Todo(int channel)
  488. {
  489.     UWORD creg;
  490.     UWORD val1,val2;
  491.  
  492.     DMA_ENTRY *tdma=&mydma[channel];
  493.  
  494.     creg=tdma->count;
  495.  
  496.     ENTER_CRITICAL;
  497.  
  498.     outportb(tdma->clear_ff,0xff);
  499.  
  500.     redo:
  501.     val1=inportb(creg);
  502.     val1|=inportb(creg)<<8;
  503.     val2=inportb(creg);
  504.     val2|=inportb(creg)<<8;
  505.  
  506.     val1-=val2;
  507.     if((SWORD)val1>64) goto redo;
  508.     if((SWORD)val1<-64) goto redo;
  509.  
  510.     LEAVE_CRITICAL;
  511.  
  512.     if(channel>3) val2<<=1;
  513.  
  514.     return val2;
  515. }
  516.