📄 emu_irq.c
字号:
/******************************************************************* User space IRQ handling emulator for i386 Linux based PCs It uses VM86_PLUS services developed for DOSEMU emu_irq.c (C) Copyright 1998 by Pavel Pisa This code is distributed under the Gnu General Public Licence. See file COPYING for details. *******************************************************************/#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <errno.h>#include <string.h>#include <asm/vm86.h>#include <sys/syscall.h>#include "emu_irq.h"#define NEW_SYS_vm86 166static inline int vm86_plus(int function, int param){ int __res; __asm__ __volatile__("int $0x80\n" :"=a" (__res):"a" ((int)NEW_SYS_vm86), "b" (function), "c" (param)); return __res;} int emu_irq_initialized=0;struct emu_irq { emu_irq_handler *handler; void *dev_id; } emu_irq_arr[16]={{0,},};void emu_irq_hanle_sig(int signo){ unsigned emu_irq_set; int intno; int ret; if(!emu_irq_initialized) return; emu_irq_set = vm86_plus(VM86_GET_IRQ_BITS,0); intno=0; while (emu_irq_set) { if((emu_irq_set&1)&&emu_irq_arr[intno].handler) { ret = vm86_plus(VM86_GET_AND_RESET_IRQ,intno); emu_irq_arr[intno].handler(intno,emu_irq_arr[intno].dev_id,NULL); }; emu_irq_set>>=1; intno++; }};void release_all_emu_irq(void);int request_emu_irq(unsigned int intno, emu_irq_handler *handler, unsigned long flags, const char *device, void *dev_id){ int ret; if(!emu_irq_initialized) { struct sigaction emu_irq_sig; struct sigaction old_sig; memset(&emu_irq_sig,0,sizeof(emu_irq_sig)); emu_irq_initialized=1; emu_irq_sig.sa_handler=emu_irq_hanle_sig; sigemptyset(&emu_irq_sig.sa_mask); emu_irq_sig.sa_flags=SA_RESTART; emu_irq_sig.sa_restorer=0; sigaction(EMU_IRQ_SIG,&emu_irq_sig,&old_sig); atexit(&release_all_emu_irq); }; if (intno>=16) return -EINVAL; if (emu_irq_arr[intno].handler) return -EINVAL; emu_irq_arr[intno].handler=handler; emu_irq_arr[intno].dev_id=dev_id; ret = vm86_plus(VM86_REQUEST_IRQ,(EMU_IRQ_SIG<<8)| intno); if (ret!=intno) { emu_irq_arr[intno].handler=NULL; return -EPERM; }; return ret;};int release_emu_irq(int intno, void *dev_id){ int ret; ret = vm86_plus(VM86_FREE_IRQ,intno); emu_irq_arr[intno].handler=NULL; return ret;};void release_all_emu_irq(void){ int intno; if(emu_irq_initialized) { for(intno=0;intno<16;intno++) if(emu_irq_arr[intno].handler!=NULL) release_emu_irq(intno,emu_irq_arr[intno].dev_id); emu_irq_initialized=0; };};/*******************************************************************//* usage example */#if 0#include <asm/io.h>#include <linux/serial_reg.h>void my_irq_handler(int intno, void *dev_id, void *regs){ int irq_src; int rec_chr; unsigned long ser_port_base=*(int *)dev_id; printf("Emulated irq %d!\n",intno); while(!((irq_src=inb(ser_port_base+UART_IIR))&UART_IIR_NO_INT)) { switch (irq_src & UART_IIR_ID) { case UART_IIR_RDI: printf("RI : "); rec_chr=inb(ser_port_base+UART_RX); printf("rec 0x%02x ",rec_chr); if (rec_chr>=' ')printf("'%c'",rec_chr); break; case UART_IIR_THRI: printf("TI : "); break; case UART_IIR_RLSI: printf("RM : "); printf("lsr 0x%02x",inb(ser_port_base+UART_LSR)); break; case UART_IIR_MSI: printf("MI : "); printf("msr 0x%02x",inb(ser_port_base+UART_MSR)); break; }; printf("\n"); };};int main(int argc, char **argv){ int ret; unsigned long ser_port_base=0x2F8; unsigned ser_irq=3; int key; int lcr_mode; int ier_enable; int baud_div; ret=ioperm(ser_port_base,8l,1); if (ret<0) { perror("cannot request ioports"); return 4;}; ret = request_emu_irq(ser_irq, my_irq_handler, 0, "test", &ser_port_base); if (ret<0) { perror("cannot request interrupt"); return 4;}; outb(0x00,ser_port_base+UART_MCR); outb(UART_LCR_DLAB,ser_port_base+UART_LCR); baud_div=12; outb(baud_div,ser_port_base+UART_DLL); outb(baud_div>>8,ser_port_base+UART_DLM); /* UART_LCR_SPAR,UART_LCR_EPAR,UART_LCR_PARITY,UART_LCR_STOP */ /* UART_LCR_WLEN8 */ lcr_mode=UART_LCR_WLEN8; outb(lcr_mode,ser_port_base+UART_LCR); ier_enable=UART_IER_MSI | UART_IER_THRI | UART_IER_RDI | UART_IER_RLSI; outb(ier_enable,ser_port_base+UART_IER); outb(UART_IIR_NO_INT,ser_port_base+UART_IIR); inb(ser_port_base+UART_LSR); inb(ser_port_base+UART_MSR); inb(ser_port_base+UART_IIR); inb(ser_port_base); outb(0x0F,ser_port_base+UART_MCR); outb(0x55,ser_port_base); do { key=getchar(); switch (key) { case 'c': outb(0x01,ser_port_base+UART_IIR); break; case 's': if(!(inb(ser_port_base+UART_IIR)&UART_IIR_NO_INT)) printf("#"); inb(ser_port_base+UART_LSR); break; case 'm': inb(ser_port_base+UART_MSR); break; case 'r': inb(ser_port_base+UART_RX); break; case 't': outb(0x55,ser_port_base+UART_TX); break; case 'l': outb(0x0D,ser_port_base+UART_TX); break; }; } while(key!='q'); // getchar(); outb(0x00,ser_port_base+UART_IER); outb(0x00,ser_port_base+UART_MCR); release_emu_irq(ser_irq, &ser_port_base); ioperm(ser_port_base,8l,0); return 0;};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -