⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dosdma.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
字号:
/*
    Implementation of DMA routines on DOS
    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "dosdma.h"

#include <dos.h>
#include <dpmi.h>
#include <sys/nearptr.h>
#include <malloc.h>

__dma_regs dma[8] = {
/* *INDENT-OFF* */
	{DMA_ADDR_0, DMA_PAGE_0, DMA_SIZE_0,
	 DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
	{DMA_ADDR_1, DMA_PAGE_1, DMA_SIZE_1,
	 DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},

	{DMA_ADDR_2, DMA_PAGE_2, DMA_SIZE_2,
	 DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
	{DMA_ADDR_3, DMA_PAGE_3, DMA_SIZE_3,
	 DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},

	{DMA_ADDR_4,          0, DMA_SIZE_4,
	 DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
	{DMA_ADDR_5, DMA_PAGE_5, DMA_SIZE_5,
	 DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},

	{DMA_ADDR_6, DMA_PAGE_6, DMA_SIZE_6,
	 DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
	{DMA_ADDR_7, DMA_PAGE_7, DMA_SIZE_7,
	 DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}
/* *INDENT-ON* */
};

static int __initialized = 0;
static int __buffer_count = 0;
static __dpmi_meminfo __locked_data;

int dma_initialize()
{
	if (!__djgpp_nearptr_enable())
		return 0;

	/* Trick: Avoid re-setting DS selector limit on each memory allocation
	   call */
	__djgpp_selector_limit = 0xffffffff;

	__locked_data.address = __djgpp_base_address + (unsigned long)&dma;
	__locked_data.size = sizeof(dma);
	if (__dpmi_lock_linear_region(&__locked_data))
		return 0;

	return (__initialized = 1);
}

void dma_finalize()
{
	if (!__initialized)
		return;
	__dpmi_unlock_linear_region(&__locked_data);
	__djgpp_nearptr_disable();
}

dma_buffer *dma_allocate(unsigned int channel, unsigned int size)
{
	int parsize = (size + 15) >> 4;	/* size in paragraphs */
	int par = 0;				/* Real-mode paragraph */
	int selector = 0;			/* Protected-mode selector */
	int mask = channel <= 3 ? 0xfff : 0x1fff;	/* Alignment mask in para. */
	int allocsize = parsize;	/* Allocated size in paragraphs */
	int count;					/* Try count */
	int bound = 0;				/* Nearest bound address */
	int maxsize;				/* Maximal possible block size */
	dma_buffer *buffer = NULL;
	__dpmi_meminfo buff_info, struct_info;

	if (!dma_initialize())
		return NULL;

	/* Loop until we'll get a properly aligned memory block */
	for (count = 8; count; count--) {
		int resize = (selector != 0);

		/* Try first to resize (possibly previously) allocated block */
		if (resize) {
			maxsize = (bound + parsize) - par;
			if (maxsize > parsize * 2)
				maxsize = parsize * 2;
			if (maxsize == allocsize)
				resize = 0;
			else {
				allocsize = maxsize;
				/* BUG WARNING: there is an error in dpmi.h DJGPP 2.01 library:
				   the order of "selector" and "alloc size" should be
				   reversed */
				if (__dpmi_resize_dos_memory(allocsize, selector, &maxsize) !=
					0) resize = 0;
			}
		}

		if (!resize) {
			if (selector)
				__dpmi_free_dos_memory(selector), selector = 0;
			par = __dpmi_allocate_dos_memory(allocsize, &selector);
		}

		if ((par == 0) || (par == -1))
			goto exit;

		/* If memory block contains a properly aligned portion, quit loop */
		bound = (par + mask + 1) & ~mask;
		if (par + parsize <= bound)
			break;
		if (bound + parsize <= par + allocsize) {
			par = bound;
			break;
		}
	}
	if (!count) {
		__dpmi_free_dos_memory(selector);
		goto exit;
	}

	buffer = malloc(sizeof(dma_buffer));
	buffer->linear = (void *)(__djgpp_conventional_base + bound * 16);
	buffer->physical = bound * 16;
	buffer->size = parsize * 16;
	buffer->selector = selector;
	buffer->channel = channel;

	buff_info.address = buffer->physical;
	buff_info.size = buffer->size;
	/*
	   Don't pay attention to return code since under plain DOS it often
	   returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI)
	 */
	__dpmi_lock_linear_region(&buff_info);

	/* Lock the DMA buffer control structure as well */
	struct_info.address = __djgpp_base_address + (unsigned long)buffer;
	struct_info.size = sizeof(dma_buffer);
	if (__dpmi_lock_linear_region(&struct_info)) {
		__dpmi_unlock_linear_region(&buff_info);
		__dpmi_free_dos_memory(selector);
		free(buffer);
		buffer = NULL;
		goto exit;
	}

  exit:
	if (buffer)
		__buffer_count++;
	else if (--__buffer_count == 0)
		dma_finalize();
	return buffer;
}

void dma_free(dma_buffer * buffer)
{
	__dpmi_meminfo buff_info;

	if (!buffer)
		return;

	buff_info.address = buffer->physical;
	buff_info.size = buffer->size;
	__dpmi_unlock_linear_region(&buff_info);

	__dpmi_free_dos_memory(buffer->selector);
	free(buffer);

	if (--__buffer_count == 0)
		dma_finalize();
}

void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode)
{
	/* Disable interrupts */
	int old_ints = disable();
	dma_disable(buffer->channel);
	dma_set_mode(buffer->channel, mode);
	dma_clear_ff(buffer->channel);
	dma_set_addr(buffer->channel, buffer->physical);
	dma_clear_ff(buffer->channel);
	dma_set_count(buffer->channel, count);
	dma_enable(buffer->channel);
	/* Re-enable interrupts */
	if (old_ints)
		enable();
}

/* ex:set ts=4: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -