📄 ppdirect.c
字号:
/*****************************************************************************//* * ppdirect.c -- Parport direct access. * * Copyright (C) 1998-1999 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 "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_direct_iobase = 0x378;unsigned int pp_direct_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)/* ---------------------------------------------------------------------- */extern inline void setecr(unsigned char ecr){ if (pp_direct_flags & FLAGS_PCECR) outb(ecr, pp_direct_iobase + LPTREG_ECONTROL);}int pp_direct_epp_clear_timeout(void){ unsigned char r; if (!(inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT)) return 1; /* To clear timeout some chips require double read */ inb(pp_direct_iobase + LPTREG_STATUS); r = inb(pp_direct_iobase + LPTREG_STATUS); outb(r | 0x01, pp_direct_iobase + LPTREG_STATUS); /* Some reset by writing 1 */ outb(r & 0xfe, pp_direct_iobase + LPTREG_STATUS); /* Others by writing 0 */ r = inb(pp_direct_iobase + LPTREG_STATUS); return !(r & 0x01);}/* ---------------------------------------------------------------------- */unsigned char parport_direct_read_data(void){ return inb(pp_direct_iobase + LPTREG_DATA);}void parport_direct_write_data(unsigned char d){ outb(d, pp_direct_iobase + LPTREG_DATA);}unsigned char parport_direct_read_status(void){ return inb(pp_direct_iobase + LPTREG_STATUS);}unsigned char parport_direct_read_control(void){ return inb(pp_direct_iobase + LPTREG_CONTROL);}void parport_direct_write_control(unsigned char d){ outb(d, pp_direct_iobase + LPTREG_CONTROL);}void parport_direct_frob_control(unsigned char mask, unsigned char val){ unsigned char d = inb(pp_direct_iobase + LPTREG_CONTROL); d = (d & (~mask)) ^ val; outb(d, pp_direct_iobase + LPTREG_CONTROL);}/* ---------------------------------------------------------------------- */unsigned parport_direct_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++) { outb(*bp, pp_direct_iobase + LPTREG_EPPDATA); if (inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { pp_direct_epp_clear_timeout(); goto rt; } ret++; } rt: setecr(0x30); /* PS/2 mode */ return ret;}unsigned parport_direct_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 = inb(pp_direct_iobase + LPTREG_EPPDATA); if (inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { pp_direct_epp_clear_timeout(); goto rt; } ret++; } rt: setecr(0x30); /* PS/2 mode */ return ret;}unsigned parport_direct_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++) { outb(*bp, pp_direct_iobase + LPTREG_EPPADDR); if (inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { pp_direct_epp_clear_timeout(); goto rt; } ret++; } rt: setecr(0x30); /* PS/2 mode */ return ret;}unsigned parport_direct_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 = inb(pp_direct_iobase + LPTREG_EPPADDR); if (inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_EPPTIMEOUT) { pp_direct_epp_clear_timeout(); goto rt; } ret++; } rt: setecr(0x30); /* PS/2 mode */ return ret;}/* ---------------------------------------------------------------------- */unsigned parport_direct_emul_epp_write_data(const void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; unsigned tmo; outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE, pp_direct_iobase + LPTREG_CONTROL); for (; sz > 0; sz--, bp++) { outb(*bp, pp_direct_iobase + LPTREG_DATA); for (tmo = 0; ; tmo++) { if (inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_WAIT) break; if (tmo > 1000) return ret; } outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE | LPTCTRL_DATASTB, pp_direct_iobase + LPTREG_CONTROL); for (tmo = 0; ; tmo++) { if (!(inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_WAIT)) break; if (tmo > 1000) return ret; } outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE, pp_direct_iobase + LPTREG_CONTROL); ret++; } return ret;}unsigned parport_direct_emul_epp_read_data(void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; unsigned tmo; outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION, pp_direct_iobase + LPTREG_CONTROL); for (; sz > 0; sz--, bp++) { for (tmo = 0; ; tmo++) { if (inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_WAIT) break; if (tmo > 1000) return ret; } outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION | LPTCTRL_DATASTB, pp_direct_iobase + LPTREG_CONTROL); for (tmo = 0; ; tmo++) { if (!(inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_WAIT)) break; if (tmo > 1000) return ret; } *bp = inb(pp_direct_iobase + LPTREG_DATA); outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION, pp_direct_iobase + LPTREG_CONTROL); ret++; } return ret;}unsigned parport_direct_emul_epp_write_addr(const void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; unsigned tmo; outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE, pp_direct_iobase + LPTREG_CONTROL); for (; sz > 0; sz--, bp++) { outb(*bp, pp_direct_iobase + LPTREG_DATA); for (tmo = 0; ; tmo++) { if (inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_WAIT) break; if (tmo > 1000) return ret; } outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE | LPTCTRL_ADDRSTB, pp_direct_iobase + LPTREG_CONTROL); for (tmo = 0; ; tmo++) { if (!(inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_WAIT)) break; if (tmo > 1000) return ret; } outb(LPTCTRL_PROGRAM | LPTCTRL_WRITE, pp_direct_iobase + LPTREG_CONTROL); ret++; } return ret;}unsigned parport_direct_emul_epp_read_addr(void *buf, unsigned sz){ unsigned char *bp = (unsigned char *)buf; unsigned ret = 0; unsigned tmo; outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION, pp_direct_iobase + LPTREG_CONTROL); for (; sz > 0; sz--, bp++) { for (tmo = 0; ; tmo++) { if (inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_WAIT) break; if (tmo > 1000) return ret; } outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION | LPTCTRL_ADDRSTB, pp_direct_iobase + LPTREG_CONTROL); for (tmo = 0; ; tmo++) { if (!(inb(pp_direct_iobase + LPTREG_STATUS) & LPTSTAT_WAIT)) break; if (tmo > 1000) return ret; } *bp = inb(pp_direct_iobase + LPTREG_DATA); outb(LPTCTRL_PROGRAM | LPTCTRL_DIRECTION, pp_direct_iobase + LPTREG_CONTROL); ret++; } return ret;}/* ---------------------------------------------------------------------- */static int ecp_forward(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -