|
@@ -280,3 +280,84 @@ static __inline__ void set_dma_page(unsigned int dmanr, unsigned int pagenr)
|
|
|
break;
|
|
|
case 3:
|
|
|
dma_outb(pagenr, DMA_PAGE_3);
|
|
|
+ dma_outb((pagenr >> 8), DMA_HIPAGE_3);
|
|
|
+ break;
|
|
|
+ case 5:
|
|
|
+ dma_outb(pagenr & 0xfe, DMA_PAGE_5);
|
|
|
+ dma_outb((pagenr >> 8), DMA_HIPAGE_5);
|
|
|
+ break;
|
|
|
+ case 6:
|
|
|
+ dma_outb(pagenr & 0xfe, DMA_PAGE_6);
|
|
|
+ dma_outb((pagenr >> 8), DMA_HIPAGE_6);
|
|
|
+ break;
|
|
|
+ case 7:
|
|
|
+ dma_outb(pagenr & 0xfe, DMA_PAGE_7);
|
|
|
+ dma_outb((pagenr >> 8), DMA_HIPAGE_7);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* Set transfer address & page bits for specific DMA channel.
|
|
|
+ * Assumes dma flipflop is clear.
|
|
|
+ */
|
|
|
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
|
|
|
+{
|
|
|
+ if (dmanr <= 3) {
|
|
|
+ dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
|
|
|
+ dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
|
|
|
+ } else {
|
|
|
+ dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
|
|
|
+ dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
|
|
|
+ }
|
|
|
+ set_dma_page(dmanr, a>>16); /* set hipage last to enable 32-bit mode */
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
|
|
|
+ * a specific DMA channel.
|
|
|
+ * You must ensure the parameters are valid.
|
|
|
+ * NOTE: from a manual: "the number of transfers is one more
|
|
|
+ * than the initial word count"! This is taken into account.
|
|
|
+ * Assumes dma flip-flop is clear.
|
|
|
+ * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
|
|
|
+ */
|
|
|
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
|
|
|
+{
|
|
|
+ count--;
|
|
|
+ if (dmanr <= 3) {
|
|
|
+ dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
|
|
|
+ dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
|
|
|
+ } else {
|
|
|
+ dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
|
|
|
+ dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* Get DMA residue count. After a DMA transfer, this
|
|
|
+ * should return zero. Reading this while a DMA transfer is
|
|
|
+ * still in progress will return unpredictable results.
|
|
|
+ * If called before the channel has been used, it may return 1.
|
|
|
+ * Otherwise, it returns the number of _bytes_ left to transfer.
|
|
|
+ *
|
|
|
+ * Assumes DMA flip-flop is clear.
|
|
|
+ */
|
|
|
+static __inline__ int get_dma_residue(unsigned int dmanr)
|
|
|
+{
|
|
|
+ unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
|
|
|
+ : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
|
|
|
+
|
|
|
+ /* using short to get 16-bit wrap around */
|
|
|
+ unsigned short count;
|
|
|
+
|
|
|
+ count = 1 + dma_inb(io_port);
|
|
|
+ count += dma_inb(io_port) << 8;
|
|
|
+
|
|
|
+ return (dmanr<=3)? count : (count<<1);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* These are in kernel/dma.c: */
|
|
|
+extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
|
|
|
+extern void free_dma(unsigned int dmanr); /* release it again */
|