11 MSDOS: BC(y) Watcom(y) DJGPP(y)
\r
17 (n) - no (not possible or not useful)
\r
18 (?) - may be possible, but not tested
\r
27 /* DMA Controler #1 (8-bit controller) */
\r
28 #define DMA1_STAT 0x08 /* read status register */
\r
29 #define DMA1_WCMD 0x08 /* write command register */
\r
30 #define DMA1_WREQ 0x09 /* write request register */
\r
31 #define DMA1_SNGL 0x0A /* write single bit register */
\r
32 #define DMA1_MODE 0x0B /* write mode register */
\r
33 #define DMA1_CLRFF 0x0C /* clear byte ptr flip/flop */
\r
34 #define DMA1_MCLR 0x0D /* master clear register */
\r
35 #define DMA1_CLRM 0x0E /* clear mask register */
\r
36 #define DMA1_WRTALL 0x0F /* write all mask register */
\r
38 /* DMA Controler #2 (16-bit controller) */
\r
39 #define DMA2_STAT 0xD0 /* read status register */
\r
40 #define DMA2_WCMD 0xD0 /* write command register */
\r
41 #define DMA2_WREQ 0xD2 /* write request register */
\r
42 #define DMA2_SNGL 0xD4 /* write single bit register */
\r
43 #define DMA2_MODE 0xD6 /* write mode register */
\r
44 #define DMA2_CLRFF 0xD8 /* clear byte ptr flip/flop */
\r
45 #define DMA2_MCLR 0xDA /* master clear register */
\r
46 #define DMA2_CLRM 0xDC /* clear mask register */
\r
47 #define DMA2_WRTALL 0xDE /* write all mask register */
\r
49 #define DMA0_ADDR 0x00 /* chan 0 base adddress */
\r
50 #define DMA0_CNT 0x01 /* chan 0 base count */
\r
51 #define DMA1_ADDR 0x02 /* chan 1 base adddress */
\r
52 #define DMA1_CNT 0x03 /* chan 1 base count */
\r
53 #define DMA2_ADDR 0x04 /* chan 2 base adddress */
\r
54 #define DMA2_CNT 0x05 /* chan 2 base count */
\r
55 #define DMA3_ADDR 0x06 /* chan 3 base adddress */
\r
56 #define DMA3_CNT 0x07 /* chan 3 base count */
\r
57 #define DMA4_ADDR 0xC0 /* chan 4 base adddress */
\r
58 #define DMA4_CNT 0xC2 /* chan 4 base count */
\r
59 #define DMA5_ADDR 0xC4 /* chan 5 base adddress */
\r
60 #define DMA5_CNT 0xC6 /* chan 5 base count */
\r
61 #define DMA6_ADDR 0xC8 /* chan 6 base adddress */
\r
62 #define DMA6_CNT 0xCA /* chan 6 base count */
\r
63 #define DMA7_ADDR 0xCC /* chan 7 base adddress */
\r
64 #define DMA7_CNT 0xCE /* chan 7 base count */
\r
66 #define DMA0_PAGE 0x87 /* chan 0 page register (refresh)*/
\r
67 #define DMA1_PAGE 0x83 /* chan 1 page register */
\r
68 #define DMA2_PAGE 0x81 /* chan 2 page register */
\r
69 #define DMA3_PAGE 0x82 /* chan 3 page register */
\r
70 #define DMA4_PAGE 0x8F /* chan 4 page register (unuseable)*/
\r
71 #define DMA5_PAGE 0x8B /* chan 5 page register */
\r
72 #define DMA6_PAGE 0x89 /* chan 6 page register */
\r
73 #define DMA7_PAGE 0x8A /* chan 7 page register */
\r
77 #define DMA_DECREMENT 0x20 /* mask to make DMA hardware go backwards */
\r
80 UBYTE dma_disable; /* bits to disable dma channel */
\r
81 UBYTE dma_enable; /* bits to enable dma channel */
\r
82 UWORD page; /* page port location */
\r
83 UWORD addr; /* addr port location */
\r
84 UWORD count; /* count port location */
\r
85 UWORD single; /* single mode port location */
\r
86 UWORD mode; /* mode port location */
\r
87 UWORD clear_ff; /* clear flip-flop port location */
\r
88 UBYTE write; /* bits for write transfer */
\r
89 UBYTE read; /* bits for read transfer */
\r
92 /* Variables needed ... */
\r
94 static DMA_ENTRY mydma[MAX_DMA] = {
\r
97 {0x04,0x00,DMA0_PAGE,DMA0_ADDR,DMA0_CNT,
\r
98 DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x48,0x44},
\r
100 /* DMA channel 1 */
\r
101 {0x05,0x01,DMA1_PAGE,DMA1_ADDR,DMA1_CNT,
\r
102 DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x49,0x45},
\r
104 /* DMA channel 2 */
\r
105 {0x06,0x02,DMA2_PAGE,DMA2_ADDR,DMA2_CNT,
\r
106 DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x4A,0x46},
\r
108 /* DMA channel 3 */
\r
109 {0x07,0x03,DMA3_PAGE,DMA3_ADDR,DMA3_CNT,
\r
110 DMA1_SNGL,DMA1_MODE,DMA1_CLRFF,0x4B,0x47},
\r
112 /* DMA channel 4 */
\r
113 {0x04,0x00,DMA4_PAGE,DMA4_ADDR,DMA4_CNT,
\r
114 DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x48,0x44},
\r
116 /* DMA channel 5 */
\r
117 {0x05,0x01,DMA5_PAGE,DMA5_ADDR,DMA5_CNT,
\r
118 DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x49,0x45},
\r
120 /* DMA channel 6 */
\r
121 {0x06,0x02,DMA6_PAGE,DMA6_ADDR,DMA6_CNT,
\r
122 DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x4A,0x46},
\r
124 /* DMA channel 7 */
\r
125 {0x07,0x03,DMA7_PAGE,DMA7_ADDR,DMA7_CNT,
\r
126 DMA2_SNGL,DMA2_MODE,DMA2_CLRFF,0x4B,0x47},
\r
132 Each specialised DMA code part should provide the following things:
\r
136 - a DMAMEM typedef, which should contain all the data that the
\r
137 routines need for maintaining/allocating/freeing dma memory.
\r
142 - 2 macros ENTER_CRITICAL and LEAVE_CRITICAL
\r
144 - A function 'static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)'
\r
145 which should perform the actual dma-memory allocation. It should
\r
146 use DMAMEM *dm to store all it's information.
\r
148 - A function 'static void MDma_FreeMem0(DMAMEM *dm)' to free the memory
\r
150 - A function 'static ULONG MDma_GetLinearPtr(DMAMEM *dm)' which should
\r
151 return the linear 20 bits pointer to the actual dmabuffer.. this
\r
152 function is used by MDma_Start
\r
154 - A function 'void *MDma_GetPtr(DMAMEM *dm)' which should return a pointer
\r
155 to the dmabuffer. If the dma memory can't be accessed directly it should
\r
156 return a pointer to a FAKE dma buffer (DJGPP!!)
\r
158 - A function 'void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)'. This
\r
159 function will be called each time a routine wrote something to the
\r
160 dmabuffer (returned by MDma_GetPtr()). In the case of a FAKE dmabuffer
\r
161 this routine should take care of copying the data from the fake buffer to
\r
162 the real dma memory ('count' bytes from byteoffset 'index').
\r
170 /****************************************************************************
\r
171 ********************* Watcom C specialised DMA code: ************************
\r
172 ****************************************************************************/
\r
174 #define ENTER_CRITICAL IRQ_PUSH_OFF()
\r
175 extern void IRQ_PUSH_OFF (void);
\r
176 #pragma aux IRQ_PUSH_OFF = \
\r
181 #define LEAVE_CRITICAL IRQ_POP()
\r
182 extern void IRQ_POP (void);
\r
183 #pragma aux IRQ_POP = \
\r
188 static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)
\r
190 Allocates a dma buffer of 'size' bytes.
\r
191 returns FALSE if failed.
\r
194 static union REGS r;
\r
197 /* allocate TWICE the size of the requested dma buffer..
\r
198 this fixes the 'page-crossing' bug of previous versions */
\r
200 r.x.eax = 0x0100; /* DPMI allocate DOS memory */
\r
201 r.x.ebx = ((size*2) + 15) >> 4; /* Number of paragraphs requested */
\r
203 int386 (0x31, &r, &r);
\r
205 if( r.x.cflag ) return 0; /* failed */
\r
207 dm->raw_selector=r.x.edx;
\r
209 /* convert the segment into a linear address */
\r
211 p=(r.x.eax&0xffff)<<4;
\r
213 /* if the first half of the allocated memory crosses a page
\r
214 boundary, return the second half which is then guaranteed to
\r
215 be page-continuous */
\r
217 if( (p>>16) != ((p+size-1)>>16) ) p+=size;
\r
219 dm->continuous=(void *)p;
\r
225 static void MDma_FreeMem0(DMAMEM *dm)
\r
227 static union REGS r;
\r
228 r.x.eax = 0x0101; /* DPMI free DOS memory */
\r
229 r.x.edx = dm->raw_selector; /* base selector */
\r
230 int386 (0x31, &r, &r);
\r
234 static ULONG MDma_GetLinearPtr(DMAMEM *dm)
\r
236 return (ULONG)dm->continuous;
\r
240 void *MDma_GetPtr(DMAMEM *dm)
\r
242 return(dm->continuous);
\r
246 void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)
\r
248 /* This function doesnt do anything here (WATCOM C
\r
249 can access dma memory directly) */
\r
253 #elif defined(__DJGPP__)
\r
254 /****************************************************************************
\r
255 *********************** DJGPP specialised DMA code: *************************
\r
256 ****************************************************************************/
\r
257 #define ENTER_CRITICAL __asm__( "pushf \n\t cli" )
\r
258 #define LEAVE_CRITICAL __asm__( "popf \n\t" )
\r
259 #include <sys/farptr.h>
\r
261 static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)
\r
263 Allocates a dma buffer of 'size' bytes - one in the code segment and
\r
264 one in the lower 1 Mb physical mem.
\r
265 It doesn't check if the dma mem is page-continuous, and can only be
\r
266 used to allocate exactly 1 block.
\r
269 dm->raw.size = (size + 15) >> 4;
\r
270 if (_go32_dpmi_allocate_dos_memory(&(dm->raw)))
\r
272 dm->continuous = (void *) malloc(size);
\r
278 static void MDma_FreeMem0(DMAMEM *dm)
\r
280 _go32_dpmi_free_dos_memory(&(dm->raw));
\r
281 free(dm->continuous);
\r
284 static ULONG MDma_GetLinearPtr(DMAMEM *dm)
\r
286 return (ULONG) dm->raw.rm_segment << 4;
\r
290 void *MDma_GetPtr(DMAMEM *dm)
\r
292 return(dm->continuous);
\r
295 void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)
\r
297 char *src = &(((UBYTE*)dm->continuous)[index]);
\r
298 ULONG dest = 16 * dm->raw.rm_segment + (ULONG) index;
\r
299 _farsetsel(_go32_conventional_mem_selector());
\r
301 _farnspokeb(dest++, *(src++));
\r
307 /****************************************************************************
\r
308 ********************* Borland C specialised DMA code: ***********************
\r
309 ****************************************************************************/
\r
311 #define ENTER_CRITICAL asm{ pushf; cli }
\r
312 #define LEAVE_CRITICAL asm{ popf }
\r
314 #define LPTR(ptr) (((ULONG)FP_SEG(ptr)<<4)+FP_OFF(ptr))
\r
315 #define NPTR(ptr) MK_FP(FP_SEG(p)+(FP_OFF(p)>>4),FP_OFF(p)&15)
\r
318 static BOOL MDma_AllocMem0(DMAMEM *dm,UWORD size)
\r
320 Allocates a dma buffer of 'size' bytes.
\r
321 returns FALSE if failed.
\r
327 /* allocate TWICE the size of the requested dma buffer..
\r
328 so we can always get a page-contiguous dma buffer */
\r
330 if((dm->raw=malloc((ULONG)size*2))==NULL) return 0;
\r
332 p=(char huge *)dm->raw;
\r
335 /* if the first half of the allocated memory crosses a page
\r
336 boundary, return the second half which is then guaranteed to
\r
337 be page-continuous */
\r
339 if( (s>>16) != ((s+size-1)>>16) ) p+=size;
\r
341 /* put the page-continuous pointer into DMAMEM */
\r
343 dm->continuous=NPTR(p);
\r
349 static void MDma_FreeMem0(DMAMEM *dm)
\r
355 static ULONG MDma_GetLinearPtr(DMAMEM *dm)
\r
357 return LPTR(dm->continuous);
\r
361 void *MDma_GetPtr(DMAMEM *dm)
\r
363 return(dm->continuous);
\r
368 void MDma_Commit(DMAMEM *dm,UWORD index,UWORD count)
\r
370 /* This function doesnt do anything here (BORLAND C
\r
371 can access dma memory directly) */
\r
377 /****************************************************************************
\r
378 ************************* General DMA code: *********************************
\r
379 ****************************************************************************/
\r
382 DMAMEM *MDma_AllocMem(UWORD size)
\r
386 /* allocate dma memory structure */
\r
388 if(!(p=(DMAMEM *)malloc(sizeof(DMAMEM)))) return NULL;
\r
390 /* allocate dma memory */
\r
392 if(!MDma_AllocMem0(p,size)){
\r
394 /* didn't succeed? -> free everything & return NULL */
\r
404 void MDma_FreeMem(DMAMEM *p)
\r
411 int MDma_Start(int channel,DMAMEM *dm,UWORD size,int type)
\r
414 ULONG s_20bit,e_20bit;
\r
415 UWORD spage,saddr,tcount;
\r
419 tdma=&mydma[channel]; /* point to this dma data */
\r
421 /* Convert the pc address to a 20 bit physical
\r
422 address that the DMA controller needs */
\r
424 s_20bit = MDma_GetLinearPtr(dm);
\r
426 e_20bit = s_20bit + size - 1;
\r
427 spage = s_20bit>>16;
\r
428 epage = e_20bit>>16;
\r
430 if(spage != epage) return 0;
\r
433 /* if 16-bit xfer, then addr,count & size are divided by 2 */
\r
434 s_20bit = s_20bit >> 1;
\r
435 e_20bit = e_20bit >> 1;
\r
439 saddr=s_20bit&0xffff;
\r
446 cur_mode = tdma->read;
\r
450 cur_mode = tdma->write;
\r
454 cur_mode = tdma->read | 0x10; /* turn on auto init */
\r
458 cur_mode = tdma->write | 0x10; /* turn on auto init */
\r
463 outportb(tdma->single,tdma->dma_disable); /* disable channel */
\r
464 outportb(tdma->mode,cur_mode); /* set mode */
\r
465 outportb(tdma->clear_ff,0); /* clear f/f */
\r
466 outportb(tdma->addr,saddr&0xff); /* LSB */
\r
467 outportb(tdma->addr,saddr>>8); /* MSB */
\r
468 outportb(tdma->page,spage); /* page # */
\r
469 outportb(tdma->clear_ff,0); /* clear f/f */
\r
470 outportb(tdma->count,tcount&0x0ff); /* LSB count */
\r
471 outportb(tdma->count,tcount>>8); /* MSB count */
\r
472 outportb(tdma->single,tdma->dma_enable); /* enable */
\r
479 void MDma_Stop(int channel)
\r
482 tdma=&mydma[channel]; /* point to this dma data */
\r
483 outportb(tdma->single,tdma->dma_disable); /* disable chan */
\r
487 UWORD MDma_Todo(int channel)
\r
492 DMA_ENTRY *tdma=&mydma[channel];
\r
498 outportb(tdma->clear_ff,0xff);
\r
501 val1=inportb(creg);
\r
502 val1|=inportb(creg)<<8;
\r
503 val2=inportb(creg);
\r
504 val2|=inportb(creg)<<8;
\r
507 if((SWORD)val1>64) goto redo;
\r
508 if((SWORD)val1<-64) goto redo;
\r
512 if(channel>3) val2<<=1;
\r