?? ppw9xring0init.c
字號:
/*****************************************************************************//* * ppw9xring0init.c -- Parport direct access under Win9x using Ring0 hack (init routines). * * 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. * *//*****************************************************************************/#if defined(HAVE_SYS_IO_H)#include <sys/io.h>#elif defined(HAVE_ASM_IO_H)#include <asm/io.h>#endif#include <errno.h>#include <string.h>#include "parport.h"/* ---------------------------------------------------------------------- */#ifndef HAVE_IOPL#ifdef HAVE_WINDOWS_H#include <windows.h>extern inline int iopl(unsigned int level){ OSVERSIONINFO info; info.dwOSVersionInfoSize = sizeof(info); if (GetVersionEx(&info) && (info.dwPlatformId == VER_PLATFORM_WIN32s || info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)) return 0; return 1;}#elseextern inline int iopl(unsigned int level){ return 0;}#endif#endif/* ---------------------------------------------------------------------- *//* 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/* ---------------------------------------------------------------------- */extern unsigned int pp_w9xring0_iobase;extern unsigned int pp_w9xring0_flags;extern const struct parport_ops parport_w9xring0_ops, parport_w9xring0_emul_ops;extern unsigned char ring0_inb(unsigned int port);extern void ring0_outb(unsigned char val, unsigned int port);extern void ring0_outsb(unsigned int port, const unsigned char *bp, unsigned int count);extern void ring0_insb(unsigned int port, unsigned char *bp, unsigned int count);extern int pp_w9xring0_epp_clear_timeout(void);#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)/* ---------------------------------------------------------------------- */#if 0#ifndef EPPEMULstatic int detect_epp(void){ /* pulse PROGRAM low, reset FPGA just to be safe */ ring0_outb(LPTCTRL_ADDRSTB, iobase+LPTREG_CONTROL); usleep(10); ring0_outb(LPTCTRL_PROGRAM, iobase+LPTREG_CONTROL); /* start of ordinary test */ if (!epp_clear_timeout()) return -1; ring0_outb(ring0_inb(iobase + LPTREG_CONTROL) | 0x20, iobase + LPTREG_CONTROL); ring0_outb(ring0_inb(iobase + LPTREG_CONTROL) | 0x10, iobase + LPTREG_CONTROL); epp_clear_timeout(); ring0_inb(iobase + LPTREG_EPPDATA); /* udelay(30); */ if (ring0_inb(iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { epp_clear_timeout(); return 0; } /*return -1;*/ lprintf(3, "warning: no EPP timeout\n"); return 0;}#endif /* !EPPEMUL */static int detect_ecr(void){ unsigned char r, oc, oec; oec = ring0_inb(iobase + LPTREG_ECONTROL); oc = ring0_inb(iobase + LPTREG_CONTROL); if ((oc & 3) == (oec & 3)) { ring0_outb(oc ^ 2, iobase + LPTREG_CONTROL); r = ring0_inb(iobase + LPTREG_CONTROL); if ((ring0_inb(iobase + LPTREG_ECONTROL) & 2) == (r & 2)) { ring0_outb(oc, iobase + LPTREG_CONTROL); return -1; } } if ((oec & 3) != 1) return -1; ring0_outb(0x34, iobase + LPTREG_ECONTROL); r = ring0_inb(iobase + LPTREG_ECONTROL); ring0_outb(oc, iobase + LPTREG_CONTROL); ring0_outb(oec, iobase + LPTREG_ECONTROL); return -(r != 0x35);}int detect_port(void){ ring0_outb(LPTCTRL_ADDRSTB, iobase+LPTREG_CONTROL); pp_w9xring0_epp_clear_timeout(); /* prevent lockup of some SMSC IC's */ /* this routine is mostly copied from Linux Kernel parport */ ring0_outb(0xc, iobase+LPTREG_ECONTROL); ring0_outb(0xc, iobase+LPTREG_CONTROL); ring0_outb(0xaa, iobase+LPTREG_DATA); if (ring0_inb(iobase+LPTREG_DATA) != 0xaa) goto fail_spp; ring0_outb(0x55, iobase+LPTREG_DATA); if (ring0_inb(iobase+LPTREG_DATA) != 0x55) goto fail_spp;#ifdef EPPEMUL /* tentatively enable PS/2 mode if ECP port */ ring0_outb(0x20, iobase + LPTREG_ECONTROL); ring0_outb(LPTCTRL_PROGRAM, iobase+LPTREG_CONTROL); if ((ring0_inb(iobase+LPTREG_CONTROL) & 0x3f) != LPTCTRL_PROGRAM) goto fail_ps2; ring0_outb(LPTCTRL_PROGRAM | LPTCTRL_W9XRING0ION, iobase+LPTREG_CONTROL); if ((ring0_inb(iobase+LPTREG_CONTROL) & 0x3f) != (LPTCTRL_PROGRAM | LPTCTRL_W9XRING0ION)) goto fail_ps2; return 0; fail_ps2: lprintf(3, "parport (PS/2 bidir) test failed\n"); return -1;#else /* !EPPEMUL */ if (!detect_ecr()) { ring0_outb(0x80, iobase + LPTREG_ECONTROL); lprintf(3, "parport SMSC style ECP+EPP detected\n"); return 0; } if (!detect_epp()) return 0; /* goto fail_epp; */ fail_epp: lprintf(3, "parport (EPP) test failed\n"); return -1;#endif /* !EPPEMUL */ fail_spp: lprintf(3, "parport (SPP) test failed\n"); return -1;}/* ---------------------------------------------------------------------- *//* * ECP routines */static void ecp_port_cap(void){ static const char *pwordstr[8] = { "2 bytes", "1 byte", "4 bytes", "3?", "4?", "5?", "6?", "7?" }; static const char *irqstr[8] = { "jumpered", "7", "9", "10", "11", "14", "15", "5" }; static const char *dmastr[8] = { "jumpered 8bit", "1", "2", "3", "jumpered 16bit", "5", "6", "7" }; unsigned char cnfga, cnfgb; unsigned int cnt, fwcnt, wthr = ~0, frcnt, rthr = ~0; ring0_outb(0x30, iobase + LPTREG_ECONTROL); /* PS/2 mode */ ring0_outb(0xf0, iobase + LPTREG_ECONTROL); /* config mode */ cnfga = ring0_inb(iobase + LPTREG_CONFIGA); cnfgb = ring0_inb(iobase + LPTREG_CONFIGB); ring0_outb(cnfgb & 0x7f, iobase + LPTREG_CONFIGB); /* disable compression */ ring0_outb(0x30, iobase + LPTREG_ECONTROL); /* PS/2 mode */ ring0_outb(0x04, iobase + LPTREG_DCR); /* w9xring0ion=output */ ring0_outb(0xd0, iobase + LPTREG_ECONTROL); /* test mode */ for (cnt = 0; cnt < 1024 && !(ring0_inb(iobase + LPTREG_ECONTROL) & 0x02); cnt++) ring0_outb(0, iobase + LPTREG_TFIFO); ring0_outb(0xd0, iobase + LPTREG_ECONTROL); /* test mode, clear serviceintr */ for (fwcnt = 0; fwcnt < 1024 && !(ring0_inb(iobase + LPTREG_ECONTROL) & 0x01); fwcnt++) { ring0_inb(iobase + LPTREG_TFIFO); if (ring0_inb(iobase + LPTREG_ECONTROL) & 0x04) { wthr = fwcnt; ring0_outb(0xd0, iobase + LPTREG_ECONTROL); /* test mode, clear serviceintr */ } } ring0_outb(0x24, iobase + LPTREG_DCR); /* w9xring0ion=input */ ring0_outb(0xd0, iobase + LPTREG_ECONTROL); /* test mode */ for (cnt = 0; cnt < 1024 && !(ring0_inb(iobase + LPTREG_ECONTROL) & 0x02); cnt++) ring0_outb(0, iobase + LPTREG_TFIFO); ring0_outb(0xd0, iobase + LPTREG_ECONTROL); /* test mode, clear serviceintr */ for (frcnt = 0; frcnt < 1024 && !(ring0_inb(iobase + LPTREG_ECONTROL) & 0x01); frcnt++) { ring0_inb(iobase + LPTREG_TFIFO); if (ring0_inb(iobase + LPTREG_ECONTROL) & 0x04) { rthr = frcnt; ring0_outb(0xd0, iobase + LPTREG_ECONTROL); /* test mode, clear serviceintr */ } } ring0_outb(0x30, iobase + LPTREG_ECONTROL); /* PS/2 mode */ ring0_outb(0x04, iobase + LPTREG_DCR); /* w9xring0ion=output */ lprintf(3, "ECP capabilities: %s int, PWord %s, %sextra tx pipe, IRQ %s, DMA %s\n" "Tx: FIFO size %d threshold %d Rx: FIFO size %d threshold %d\n", (cnfga & 0x80) ? "level" : "edge", pwordstr[(cnfga >> 4) & 7], (cnfga & 0x04) ? "no" : "", irqstr[(cnfgb >> 3) & 7], dmastr[cnfgb & 7], fwcnt, wthr, frcnt, rthr);}int detect_port_ecp(void){ epp_clear_timeout(); /* prevent lockup of some SMSC IC's */ /* this routine is mostly copied from Linux Kernel parport */ ring0_outb(0xc, iobase+LPTREG_ECONTROL); ring0_outb(0xc, iobase+LPTREG_CONTROL); ring0_outb(0xaa, iobase+LPTREG_DATA); if (ring0_inb(iobase+LPTREG_DATA) != 0xaa) goto fail_spp; ring0_outb(0x55, iobase+LPTREG_DATA); if (ring0_inb(iobase+LPTREG_DATA) != 0x55) goto fail_spp; /* check for ECP ECR mode */ if (detect_ecr()) goto fail_ecp; ecp_port_cap(); return 0; fail_ecp: lprintf(0, "parport (ECP) test failed\n"); return -1; fail_spp: lprintf(0, "parport (SPP) test failed\n"); return -1;}#endif/* ---------------------------------------------------------------------- */static int parport_spp(void){ pp_w9xring0_epp_clear_timeout(); /* prevent lockup of some SMSC IC's */ /* this routine is mostly copied from Linux Kernel parport */ ring0_outb(0xc, pp_w9xring0_iobase+LPTREG_ECONTROL); ring0_outb(0xc, pp_w9xring0_iobase+LPTREG_CONTROL); ring0_outb(0xaa, pp_w9xring0_iobase+LPTREG_DATA); if (ring0_inb(pp_w9xring0_iobase+LPTREG_DATA) != 0xaa) return 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -