📄 ppw9xring0.c
字号:
/*****************************************************************************//* * ppw9xring0.c -- Parport direct access under Win9x using Ring0 hack. * * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Please note that the GPL allows you to use the driver, NOT the radio. * In order to use the radio, you need a license from the communications * authority of your country. * *//*****************************************************************************/#include <windows.h>#include "parport.h"/* ---------------------------------------------------------------------- *//* LPT registers *//* ECP specific registers */#define LPTREG_ECONTROL 0x402#define LPTREG_CONFIGB 0x401#define LPTREG_CONFIGA 0x400#define LPTREG_TFIFO 0x400#define LPTREG_DFIFO 0x400#define LPTREG_AFIFO 0x000#define LPTREG_DSR 0x001#define LPTREG_DCR 0x002/* EPP specific registers */#define LPTREG_EPPDATA 0x004#define LPTREG_EPPADDR 0x003/* standard registers */#define LPTREG_CONTROL 0x002#define LPTREG_STATUS 0x001#define LPTREG_DATA 0x000/* ECP config A */#define LPTCFGA_INTRISALEVEL 0x80#define LPTCFGA_IMPIDMASK 0x70#define LPTCFGA_IMPID16BIT 0x00#define LPTCFGA_IMPID8BIT 0x10#define LPTCFGA_IMPID32BIT 0x20#define LPTCFGA_NOPIPELINE 0x04#define LPTCFGA_PWORDCOUNT 0x03/* ECP config B */#define LPTCFGB_COMPRESS 0x80#define LPTCFGB_INTRVALUE 0x40#define LPTCFGB_IRQMASK 0x38#define LPTCFGB_IRQ5 0x38#define LPTCFGB_IRQ15 0x30#define LPTCFGB_IRQ14 0x28#define LPTCFGB_IRQ11 0x20#define LPTCFGB_IRQ10 0x18#define LPTCFGB_IRQ9 0x10#define LPTCFGB_IRQ7 0x08#define LPTCFGB_IRQJUMPER 0x00#define LPTCFGB_DMAMASK 0x07#define LPTCFGB_DMA7 0x07#define LPTCFGB_DMA6 0x06#define LPTCFGB_DMA5 0x05#define LPTCFGB_DMAJUMPER16 0x04#define LPTCFGB_DMA3 0x03#define LPTCFGB_DMA2 0x02#define LPTCFGB_DMA1 0x01#define LPTCFGB_DMAJUMPER8 0x00/* ECP ECR */#define LPTECR_MODEMASK 0xe0#define LPTECR_MODESPP 0x00#define LPTECR_MODEPS2 0x20#define LPTECR_MODESPPFIFO 0x40#define LPTECR_MODEECP 0x60#define LPTECR_MODEECPEPP 0x80#define LPTECR_MODETEST 0xc0#define LPTECR_MODECFG 0xe0#define LPTECR_NERRINTRDIS 0x10#define LPTECR_DMAEN 0x08#define LPTECR_SERVICEINTR 0x04#define LPTECR_FIFOFULL 0x02#define LPTECR_FIFOEMPTY 0x01/* ---------------------------------------------------------------------- */unsigned int pp_w9xring0_iobase = 0x378;unsigned int pp_w9xring0_flags = 0;#define FLAGS_PCSPP (1<<0)#define FLAGS_PCPS2 (1<<1)#define FLAGS_PCEPP (1<<2)#define FLAGS_PCECR (1<<3) /* ECR Register Exists */#define FLAGS_PCECP (1<<4)#define FLAGS_PCECPEPP (1<<5)#define FLAGS_PCECPPS2 (1<<6)/* ---------------------------------------------------------------------- */asm(".text\n\t" ".align\t4\n" "_do_ring0_inb:\n\t" "inb %dx,%al\n\t" "lret\n\n\t" ".align\t4\n" "_do_ring0_outb:\n\t" "outb %al,%dx\n\t" "lret\n\n\t" ".align\t4\n\t" ".data\n\t");extern int do_ring0_inb(int,int);extern int do_ring0_outb(int,int);static int call_ring0(int (*routine)(int,int), int param1, int param2){ unsigned short gdtbase[3]; unsigned short callgateaddr[3]; struct gdt { unsigned short offslo; unsigned short selector; unsigned short flags; unsigned short offshi; } *gdt, *mygdt; unsigned int i, maxgdt; int ret; asm("sgdt\t%0" : "=m" (gdtbase)); gdt = (struct gdt *)((gdtbase[2] << 16) | gdtbase[1]); maxgdt = gdtbase[0]/8; /* gdt limit */ for (i = 1; i < maxgdt; i++) { if (!gdt[i].flags && !gdt[i].selector && !gdt[i].offslo && !gdt[i].offshi) break; } if (i >= maxgdt) { lprintf(3, "Cannot find free GDT entry\n"); return -1; } mygdt = &gdt[i]; mygdt->flags = (1 << 15) | /* present */ (0x0c00) | /* type: call gate */ (3 << 13) | /* DPL */ 0; /* dword count */ mygdt->selector = 0x28; mygdt->offslo = ((unsigned long)routine); mygdt->offshi = ((unsigned long)routine) >> 16; callgateaddr[0] = callgateaddr[1] = 0; callgateaddr[2] = (i << 3) | 3; asm("lcall\t%1" : "=a" (ret) : "m" (callgateaddr[0]), "d" (param1), "0" (param2) : "memory"); memset(mygdt, 0, sizeof(struct gdt)); return ret;}unsigned char ring0_inb(unsigned int port){ return call_ring0(do_ring0_inb, port, 0);}void ring0_outb(unsigned char val, unsigned int port){ call_ring0(do_ring0_outb, port, val);}void ring0_outsb(unsigned int port, const unsigned char *bp, unsigned int count){ while (count > 0) { ring0_outb(*bp++, port); count--; }}void ring0_insb(unsigned int port, unsigned char *bp, unsigned int count){ while (count > 0) { *bp++ = ring0_inb(port); count--; }}/* ---------------------------------------------------------------------- */extern inline void setecr(unsigned char ecr){ if (pp_w9xring0_flags & FLAGS_PCECR) ring0_outb(ecr, pp_w9xring0_iobase + LPTREG_ECONTROL);}int pp_w9xring0_epp_clear_timeout(void){ unsigned char r; if (!(ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT)) return 1; /* To clear timeout some chips require double read */ ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS); r = ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS); ring0_outb(r | 0x01, pp_w9xring0_iobase + LPTREG_STATUS); /* Some reset by writing 1 */ ring0_outb(r & 0xfe, pp_w9xring0_iobase + LPTREG_STATUS); /* Others by writing 0 */ r = ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS); return !(r & 0x01);}/* ---------------------------------------------------------------------- */unsigned char parport_w9xring0_read_data(void){ return ring0_inb(pp_w9xring0_iobase + LPTREG_DATA);}void parport_w9xring0_write_data(unsigned char d){ ring0_outb(d, pp_w9xring0_iobase + LPTREG_DATA);}unsigned char parport_w9xring0_read_status(void){ return ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS);}unsigned char parport_w9xring0_read_control(void){ return ring0_inb(pp_w9xring0_iobase + LPTREG_CONTROL);}void parport_w9xring0_write_control(unsigned char d){ ring0_outb(d, pp_w9xring0_iobase + LPTREG_CONTROL);}void parport_w9xring0_frob_control(unsigned char mask, unsigned char val){ unsigned char d = ring0_inb(pp_w9xring0_iobase + LPTREG_CONTROL); d = (d & (~mask)) ^ val; ring0_outb(d, pp_w9xring0_iobase + LPTREG_CONTROL);}/* ---------------------------------------------------------------------- */unsigned parport_w9xring0_epp_write_data(const void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; setecr(0x90); /* EPP mode */ for (; sz > 0; sz--, bp++) { ring0_outb(*bp, pp_w9xring0_iobase + LPTREG_EPPDATA); if (ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { pp_w9xring0_epp_clear_timeout(); goto rt; } ret++; } rt: setecr(0x30); /* PS/2 mode */ return ret;}unsigned parport_w9xring0_epp_read_data(void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; setecr(0x90); /* EPP mode */ for (; sz > 0; sz--, bp++) { *bp = ring0_inb(pp_w9xring0_iobase + LPTREG_EPPDATA); if (ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { pp_w9xring0_epp_clear_timeout(); goto rt; } ret++; } rt: setecr(0x30); /* PS/2 mode */ return ret;}unsigned parport_w9xring0_epp_write_addr(const void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; setecr(0x90); /* EPP mode */ for (; sz > 0; sz--, bp++) { ring0_outb(*bp, pp_w9xring0_iobase + LPTREG_EPPADDR); if (ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { pp_w9xring0_epp_clear_timeout(); goto rt; } ret++; } rt: setecr(0x30); /* PS/2 mode */ return ret;}unsigned parport_w9xring0_epp_read_addr(void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; setecr(0x90); /* EPP mode */ for (; sz > 0; sz--, bp++) { *bp = ring0_inb(pp_w9xring0_iobase + LPTREG_EPPADDR); if (ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { pp_w9xring0_epp_clear_timeout(); goto rt; } ret++; } rt: setecr(0x30); /* PS/2 mode */ return ret;}/* ---------------------------------------------------------------------- */unsigned parport_w9xring0_emul_epp_write_data(const void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; unsigned tmo; ring0_outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE, pp_w9xring0_iobase + LPTREG_CONTROL); for (; sz > 0; sz--, bp++) { ring0_outb(*bp, pp_w9xring0_iobase + LPTREG_DATA); for (tmo = 0; ; tmo++) { if (ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_WAIT) break; if (tmo > 1000) return ret; } ring0_outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE | LPTCTRL_DATASTB, pp_w9xring0_iobase + LPTREG_CONTROL); for (tmo = 0; ; tmo++) { if (!(ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_WAIT)) break; if (tmo > 1000) return ret; } ring0_outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE, pp_w9xring0_iobase + LPTREG_CONTROL); ret++; } return ret;}unsigned parport_w9xring0_emul_epp_read_data(void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; unsigned tmo; ring0_outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION, pp_w9xring0_iobase + LPTREG_CONTROL); for (; sz > 0; sz--, bp++) { for (tmo = 0; ; tmo++) { if (ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_WAIT) break; if (tmo > 1000) return ret; } ring0_outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION | LPTCTRL_DATASTB, pp_w9xring0_iobase + LPTREG_CONTROL); for (tmo = 0; ; tmo++) { if (!(ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_WAIT)) break; if (tmo > 1000) return ret; } *bp = ring0_inb(pp_w9xring0_iobase + LPTREG_DATA); ring0_outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION, pp_w9xring0_iobase + LPTREG_CONTROL); ret++; } return ret;}unsigned parport_w9xring0_emul_epp_write_addr(const void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; unsigned tmo; ring0_outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE, pp_w9xring0_iobase + LPTREG_CONTROL); for (; sz > 0; sz--, bp++) { ring0_outb(*bp, pp_w9xring0_iobase + LPTREG_DATA); for (tmo = 0; ; tmo++) { if (ring0_inb(pp_w9xring0_iobase + LPTREG_STATUS) & LPTSTAT_WAIT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -