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

📄 dosirq.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
字号:
/*
    Implementation of IRQ 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 "dosirq.h"

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

unsigned int __irq_stack_size = 0x4000;
unsigned int __irq_stack_count = 1;

static void __int_stub_template()
{
/* *INDENT-OFF* */
	asm("	pushal\n"
		"	pushl	%ds\n"
		"	pushl	%es\n"
		"	pushl	%fs\n"
		"	pushl	%gs\n"
		"	movw	$0x1234,%ax\n"		/* Get DPMI data selector */
		"	movw	%ax,%ds\n"			/* Set DS and ES to data selector */
		"	movw	%ax,%es\n"
		"	movl	$0x12345678,%ebx\n"	/* Interrupt stack top */
		"	movl	(%ebx),%ecx\n"
		"	movl	%ecx,%edx\n"
		"	subl	$0x12345678,%ecx\n"	/* Subtract irq_stack_count */
		"	movl	%ecx,(%ebx)\n"
		"	movw	%ss,%si\n"			/* Save old SS:ESP */
		"	movl	%esp,%edi\n"
		"	movl	%edx,%esp\n"		/* Set SS:ESP to interrupt stack */
		"	movw	%ax,%ss\n"
		"	pushl	%esi\n"
		"	pushl	%edi\n"
		"	pushl	%ebx\n"
		"	pushl	%edx\n"
		"	call	1f\n"				/* Call user interrupt handler */
		"1:	popl	%edx\n"
		"	popl	%ebx\n"
		"	movl	%edx,(%ebx)\n"
		"	popl	%edi\n"
		"	popl	%esi\n"
		"	movl	%edi,%esp\n"		/* Restore old SS:ESP */
		"	movw	%si,%ss\n"
		"	popl	%gs\n"
		"	popl	%fs\n"
		"	popl	%es\n"
		"	popl	%ds\n"
		"	popal\n"
		"	iret\n");
/* *INDENT-ON* */
}

#include <stdio.h>

static int _allocate_iret_wrapper(_go32_dpmi_seginfo * info)
{
	unsigned char *irqtpl = (unsigned char *)__int_stub_template;
	unsigned char *irqend, *irqwrapper, *tmp;
	__dpmi_meminfo handler_info;
	unsigned int wrappersize;

	/* First, skip until pushal */
	while (*irqtpl != 0x60)
		irqtpl++;
	/* Now find the iret */
	irqend = irqtpl;
	while (*irqend++ != 0xcf);

	wrappersize = 4 + __irq_stack_size * __irq_stack_count + 4 +
	  ((long)irqend - (long)irqtpl);
	irqwrapper = malloc(wrappersize);
	/* Lock the wrapper */
	handler_info.address = __djgpp_base_address + (unsigned long)irqwrapper;
	handler_info.size = wrappersize;
	if (__dpmi_lock_linear_region(&handler_info)) {
		free(irqwrapper);
		return -1;
	}

	/* First comes the interrupt wrapper size */
	*(unsigned long *)irqwrapper = wrappersize;

	/* Next comes the interrupt stack */
	tmp = irqwrapper + 4 + __irq_stack_size * __irq_stack_count;

	/* The following dword is interrupt stack pointer */
	*((void **)tmp) = tmp;
	tmp += 4;

	/* Now comes the interrupt wrapper itself */
	memcpy(tmp, irqtpl, irqend - irqtpl);
	*(unsigned short *)(tmp + 9) = _my_ds();
	*(unsigned long *)(tmp + 16) = (unsigned long)tmp - 4;
	*(unsigned long *)(tmp + 26) = __irq_stack_size;
	*(unsigned long *)(tmp + 46) =
	  info->pm_offset - (unsigned long)(tmp + 50);

	info->pm_offset = (unsigned long)tmp;
	info->pm_selector = _my_cs();

	return 0;
}

static void _free_iret_wrapper(_go32_dpmi_seginfo * info)
{
	__dpmi_meminfo handler_info;

	info->pm_offset -= 4 + __irq_stack_size * __irq_stack_count + 4;

	handler_info.address = __djgpp_base_address + info->pm_offset;
	handler_info.size = *(unsigned long *)info->pm_offset;
	__dpmi_unlock_linear_region(&handler_info);

	free((void *)info->pm_offset);
}

irq_handle *irq_hook(int irqno, void (*handler) (), unsigned long size)
{
	int interrupt;
	irq_handle *irq;
	__dpmi_version_ret version;
	__dpmi_meminfo handler_info, struct_info;
	_go32_dpmi_seginfo info;
	unsigned long old_sel, old_ofs;

	__dpmi_get_version(&version);
	if (irqno < 8)
		interrupt = version.master_pic + irqno;
	else
		interrupt = version.slave_pic + (irqno - 8);

	if (_go32_dpmi_get_protected_mode_interrupt_vector(interrupt, &info))
		return NULL;

	old_sel = info.pm_selector;
	old_ofs = info.pm_offset;

	info.pm_offset = (unsigned long)handler;
	if (_allocate_iret_wrapper(&info))
		return NULL;

	/* Lock the interrupt handler in memory */
	handler_info.address = __djgpp_base_address + (unsigned long)handler;
	handler_info.size = size;
	if (__dpmi_lock_linear_region(&handler_info)) {
		_free_iret_wrapper(&info);
		return NULL;
	}

	irq = malloc(sizeof(irq_handle));
	irq->c_handler = handler;
	irq->handler_size = size;
	irq->handler = info.pm_offset;
	irq->prev_selector = old_sel;
	irq->prev_offset = old_ofs;
	irq->int_num = interrupt;
	irq->irq_num = irqno;
	irq->pic_base = irqno < 8 ? PIC1_BASE : PIC2_BASE;

	struct_info.address = __djgpp_base_address + (unsigned long)irq;
	struct_info.size = sizeof(irq_handle);
	if (__dpmi_lock_linear_region(&struct_info)) {
		free(irq);
		__dpmi_unlock_linear_region(&handler_info);
		_free_iret_wrapper(&info);
		return NULL;
	}

	_go32_dpmi_set_protected_mode_interrupt_vector(interrupt, &info);

	irq->pic_mask = irq_state(irq);
	return irq;
}

void irq_unhook(irq_handle * irq)
{
	_go32_dpmi_seginfo info;
	__dpmi_meminfo mem_info;

	if (!irq)
		return;

	/* Restore the interrupt vector */
	irq_disable(irq);
	info.pm_offset = irq->prev_offset;
	info.pm_selector = irq->prev_selector;
	_go32_dpmi_set_protected_mode_interrupt_vector(irq->int_num, &info);

	/* Unlock the interrupt handler */
	mem_info.address = __djgpp_base_address + (unsigned long)irq->c_handler;
	mem_info.size = irq->handler_size;
	__dpmi_unlock_linear_region(&mem_info);

	/* Unlock the irq_handle structure */
	mem_info.address = __djgpp_base_address + (unsigned long)irq;
	mem_info.size = sizeof(irq_handle);
	__dpmi_unlock_linear_region(&mem_info);

	info.pm_offset = irq->handler;
	_free_iret_wrapper(&info);

	/* If IRQ was enabled before we hooked, restore enabled state */
	if (irq->pic_mask)
		irq_enable(irq);
	else
		irq_disable(irq);

	free(irq);
}

/*---------------------------------------------- IRQ detection mechanism -----*/
static irq_handle *__irqs[16];
static int (*__irq_confirm) (int irqno);
static volatile unsigned int __irq_mask;
static volatile unsigned int __irq_count[16];

#define DECLARE_IRQ_HANDLER(irqno)							\
static void __irq##irqno##_handler ()						\
{															\
  if (irq_check (__irqs [irqno]) && __irq_confirm (irqno))	\
  {															\
    __irq_count [irqno]++;									\
    __irq_mask |= (1 << irqno);								\
  }															\
  irq_ack (__irqs [irqno]);									\
}

/* *INDENT-OFF* */
DECLARE_IRQ_HANDLER(0)
DECLARE_IRQ_HANDLER(1)
DECLARE_IRQ_HANDLER(2)
DECLARE_IRQ_HANDLER(3)
DECLARE_IRQ_HANDLER(4)
DECLARE_IRQ_HANDLER(5)
DECLARE_IRQ_HANDLER(6)
DECLARE_IRQ_HANDLER(7)
DECLARE_IRQ_HANDLER(8)
DECLARE_IRQ_HANDLER(9)
DECLARE_IRQ_HANDLER(10)
DECLARE_IRQ_HANDLER(11)
DECLARE_IRQ_HANDLER(12)
DECLARE_IRQ_HANDLER(13)
DECLARE_IRQ_HANDLER(14)
DECLARE_IRQ_HANDLER(15)
/* *INDENT-ON* */

static void (*__irq_handlers[16]) () = {
	__irq0_handler, __irq1_handler, __irq2_handler, __irq3_handler,
	  __irq4_handler, __irq5_handler, __irq6_handler, __irq7_handler,
	  __irq8_handler, __irq9_handler, __irq10_handler, __irq11_handler,
	  __irq12_handler, __irq13_handler, __irq14_handler, __irq15_handler};

void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno))
{
	int i;

	__irq_mask = 0;
	__irq_confirm = irq_confirm;
	memset(&__irqs, 0, sizeof(__irqs));
	memset(&__irq_count, 0, sizeof(__irq_count));

	/* Hook all specified IRQs */
	for (i = 1; i <= 15; i++)
		if (irqs & (1 << i)) {
			__irqs[i] = irq_hook(i, __irq_handlers[i], 200);
			/* Enable the interrupt */
			irq_enable(__irqs[i]);
		}
	/* Enable IRQ2 if we need at least one IRQ above 7 */
	if (irqs & 0xff00)
		_irq_enable(2);
}

void irq_detect_end()
{
	int i;
	for (i = 15; i >= 1; i--)
		if (__irqs[i])
			irq_unhook(__irqs[i]);
}

int irq_detect_get(int irqno, int *irqmask)
{
	int oldirq = disable();
	int count = __irq_count[irqno];
	*irqmask = __irq_mask;
	__irq_mask = 0;
	if (oldirq)
		enable();
	return count;
}

void irq_detect_clear()
{
	int oldirq = disable();
	memset(&__irq_count, 0, sizeof(__irq_count));
	__irq_mask = 0;
	if (oldirq)
		enable();
}

/* ex:set ts=4: */

⌨️ 快捷键说明

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