mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Major ppbus updates from the author.
- ppbus now supports PLIP via the if_plip driver - ieee1284 infrastructure added, including parallel-port PnP - port microsequencer added, for scripting the sort of port I/O that is common with parallel devices without endless calls up and down through the driver structure. - improved bus ownership behaviour among the ppbus-using drivers. - improved I/O chipset feature detection The vpo driver is now implemented using the microsequencer, leading to some performance improvements as well as providing an extensive example of its use. Reviewed by: msmith Submitted by: Nicolas Souchu <Nicolas.Souchu@prism.uvsq.fr>
This commit is contained in:
parent
90afb6a523
commit
46f3ff7986
23 changed files with 4298 additions and 1373 deletions
|
|
@ -2,7 +2,7 @@
|
|||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.446 1998/07/11 04:46:27 julian Exp $
|
||||
# $Id: LINT,v 1.447 1998/07/20 20:00:30 msmith Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
|
|
@ -1440,6 +1440,7 @@ options POWERFAIL_NMI # make it beep instead of panicing
|
|||
# Requires SCSI disk support ('scbus' and 'sd'), best
|
||||
# performance is achieved with ports in EPP 1.9 mode.
|
||||
# nlpt Parallel Printer
|
||||
# plip Parallel network interface
|
||||
# ppi General-purpose I/O ("Geek Port")
|
||||
#
|
||||
# Supported interfaces:
|
||||
|
|
@ -1448,6 +1449,7 @@ options POWERFAIL_NMI # make it beep instead of panicing
|
|||
controller ppbus0
|
||||
controller vpo0 at ppbus?
|
||||
device nlpt0 at ppbus?
|
||||
device plip0 at ppbus?
|
||||
device ppi0 at ppbus?
|
||||
device pps0 at ppbus?
|
||||
|
||||
|
|
|
|||
|
|
@ -53,10 +53,13 @@ dev/pdq/pdq_ifsubr.c optional fpa device-driver
|
|||
dev/ppbus/nlpt.c optional nlpt
|
||||
dev/ppbus/ppb_base.c optional ppbus
|
||||
dev/ppbus/ppb_1284.c optional ppbus
|
||||
dev/ppbus/ppb_msq.c optional ppbus
|
||||
dev/ppbus/ppbconf.c optional ppbus
|
||||
dev/ppbus/ppi.c optional ppi
|
||||
dev/ppbus/pps.c optional pps
|
||||
dev/ppbus/vpo.c optional vpo
|
||||
dev/ppbus/vpoio.c optional vpo
|
||||
dev/ppbus/if_plip.c optional plip
|
||||
dev/slice/slice_base.c optional slice
|
||||
dev/slice/slice_device.c optional slice
|
||||
dev/slice/mbr.c optional slice
|
||||
|
|
|
|||
772
sys/dev/ppbus/if_plip.c
Normal file
772
sys/dev/ppbus/if_plip.c
Normal file
|
|
@ -0,0 +1,772 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Poul-Henning Kamp
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parallel port TCP/IP interfaces added. I looked at the driver from
|
||||
* MACH but this is a complete rewrite, and btw. incompatible, and it
|
||||
* should perform better too. I have never run the MACH driver though.
|
||||
*
|
||||
* This driver sends two bytes (0x08, 0x00) in front of each packet,
|
||||
* to allow us to distinguish another format later.
|
||||
*
|
||||
* Now added an Linux/Crynwr compatibility mode which is enabled using
|
||||
* IF_LINK0 - Tim Wilkinson.
|
||||
*
|
||||
* TODO:
|
||||
* Make HDLC/PPP mode, use IF_LLC1 to enable.
|
||||
*
|
||||
* Connect the two computers using a Laplink parallel cable to use this
|
||||
* feature:
|
||||
*
|
||||
* +----------------------------------------+
|
||||
* |A-name A-End B-End Descr. Port/Bit |
|
||||
* +----------------------------------------+
|
||||
* |DATA0 2 15 Data 0/0x01 |
|
||||
* |-ERROR 15 2 1/0x08 |
|
||||
* +----------------------------------------+
|
||||
* |DATA1 3 13 Data 0/0x02 |
|
||||
* |+SLCT 13 3 1/0x10 |
|
||||
* +----------------------------------------+
|
||||
* |DATA2 4 12 Data 0/0x04 |
|
||||
* |+PE 12 4 1/0x20 |
|
||||
* +----------------------------------------+
|
||||
* |DATA3 5 10 Strobe 0/0x08 |
|
||||
* |-ACK 10 5 1/0x40 |
|
||||
* +----------------------------------------+
|
||||
* |DATA4 6 11 Data 0/0x10 |
|
||||
* |BUSY 11 6 1/~0x80 |
|
||||
* +----------------------------------------+
|
||||
* |GND 18-25 18-25 GND - |
|
||||
* +----------------------------------------+
|
||||
*
|
||||
* Expect transfer-rates up to 75 kbyte/sec.
|
||||
*
|
||||
* If GCC could correctly grok
|
||||
* register int port asm("edx")
|
||||
* the code would be cleaner
|
||||
*
|
||||
* Poul-Henning Kamp <phk@freebsd.org>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Update for ppbus, PLIP support only - Nicolas Souchu
|
||||
*/
|
||||
|
||||
#ifdef KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/netisr.h>
|
||||
|
||||
#endif /* KERNEL */
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include "bpfilter.h"
|
||||
#if NBPFILTER > 0
|
||||
#include <net/bpf.h>
|
||||
#include <net/bpfdesc.h>
|
||||
#endif
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/nlpt.h>
|
||||
|
||||
#ifndef LPMTU /* MTU for the lp# interfaces */
|
||||
#define LPMTU 1500
|
||||
#endif
|
||||
|
||||
#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */
|
||||
#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */
|
||||
#endif
|
||||
|
||||
#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */
|
||||
#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */
|
||||
#endif
|
||||
|
||||
#ifndef LPMAXERRS /* Max errors before !RUNNING */
|
||||
#define LPMAXERRS 100
|
||||
#endif
|
||||
|
||||
#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */
|
||||
#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */
|
||||
#define MLPIPHDRLEN CLPIPHDRLEN
|
||||
|
||||
#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */
|
||||
#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */
|
||||
#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
|
||||
#define MLPIPHDRLEN LPIPHDRLEN
|
||||
#endif
|
||||
|
||||
#define LPIPTBLSIZE 256 /* Size of octet translation table */
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifndef DEBUG
|
||||
#define lprintf (void)
|
||||
#else
|
||||
#define lprintf if (lptflag) printf
|
||||
static int volatile lptflag = 1;
|
||||
#endif
|
||||
|
||||
struct lpt_softc {
|
||||
unsigned short lp_unit;
|
||||
|
||||
struct ppb_device lp_dev;
|
||||
|
||||
struct ifnet sc_if;
|
||||
u_char *sc_ifbuf;
|
||||
int sc_iferrs;
|
||||
};
|
||||
|
||||
static int nlp = 0;
|
||||
#define MAXPLIP 8 /* XXX not much better! */
|
||||
static struct lpt_softc *lpdata[MAXPLIP];
|
||||
|
||||
|
||||
/* Tables for the lp# interface */
|
||||
static u_char *txmith;
|
||||
#define txmitl (txmith+(1*LPIPTBLSIZE))
|
||||
#define trecvh (txmith+(2*LPIPTBLSIZE))
|
||||
#define trecvl (txmith+(3*LPIPTBLSIZE))
|
||||
|
||||
static u_char *ctxmith;
|
||||
#define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
|
||||
#define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
|
||||
#define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
|
||||
|
||||
/* Functions for the lp# interface */
|
||||
static struct ppb_device *lpprobe(struct ppb_data *);
|
||||
static int lpattach(struct ppb_device *);
|
||||
|
||||
static int lpinittables(void);
|
||||
static int lpioctl(struct ifnet *, u_long, caddr_t);
|
||||
static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
|
||||
struct rtentry *);
|
||||
static void lpintr(int);
|
||||
|
||||
/*
|
||||
* Make ourselves visible as a ppbus driver
|
||||
*/
|
||||
|
||||
static struct ppb_driver lpdriver = {
|
||||
lpprobe, lpattach, "lp"
|
||||
};
|
||||
DATA_SET(ppbdriver_set, lpdriver);
|
||||
|
||||
|
||||
/*
|
||||
* lpprobe()
|
||||
*/
|
||||
static struct ppb_device *
|
||||
lpprobe(struct ppb_data *ppb)
|
||||
{
|
||||
struct lpt_softc *lp;
|
||||
|
||||
/* if we haven't interrupts, the probe fails */
|
||||
if (!ppb->ppb_link->id_irq)
|
||||
return (0);
|
||||
|
||||
lp = (struct lpt_softc *) malloc(sizeof(struct lpt_softc),
|
||||
M_TEMP, M_NOWAIT);
|
||||
if (!lp) {
|
||||
printf("lp: cannot malloc!\n");
|
||||
return (0);
|
||||
}
|
||||
bzero(lp, sizeof(struct lpt_softc));
|
||||
|
||||
lpdata[nlp] = lp;
|
||||
|
||||
/*
|
||||
* lp dependent initialisation.
|
||||
*/
|
||||
lp->lp_unit = nlp;
|
||||
|
||||
if (bootverbose)
|
||||
printf("plip: irq %d", ppb->ppb_link->id_irq);
|
||||
|
||||
/*
|
||||
* ppbus dependent initialisation.
|
||||
*/
|
||||
lp->lp_dev.id_unit = lp->lp_unit;
|
||||
lp->lp_dev.name = lpdriver.name;
|
||||
lp->lp_dev.ppb = ppb;
|
||||
lp->lp_dev.intr = lpintr;
|
||||
|
||||
/* Ok, go to next device on next probe */
|
||||
nlp ++;
|
||||
|
||||
return (&lp->lp_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
lpattach (struct ppb_device *dev)
|
||||
{
|
||||
int unit = dev->id_unit;
|
||||
struct lpt_softc *sc = lpdata[unit];
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
|
||||
/*
|
||||
* Report ourselves
|
||||
*/
|
||||
printf("plip%d: <PLIP network interface> on ppbus %d\n",
|
||||
dev->id_unit, dev->ppb->ppb_link->adapter_unit);
|
||||
|
||||
ifp->if_softc = sc;
|
||||
ifp->if_name = "lp";
|
||||
ifp->if_unit = unit;
|
||||
ifp->if_mtu = LPMTU;
|
||||
ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
|
||||
ifp->if_ioctl = lpioctl;
|
||||
ifp->if_output = lpoutput;
|
||||
ifp->if_type = IFT_PARA;
|
||||
ifp->if_hdrlen = 0;
|
||||
ifp->if_addrlen = 0;
|
||||
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
|
||||
if_attach(ifp);
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfattach(ifp, DLT_NULL, LPIPHDRLEN);
|
||||
#endif
|
||||
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* Build the translation tables for the LPIP (BSD unix) protocol.
|
||||
* We don't want to calculate these nasties in our tight loop, so we
|
||||
* precalculate them when we initialize.
|
||||
*/
|
||||
static int
|
||||
lpinittables (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!txmith)
|
||||
txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
|
||||
|
||||
if (!txmith)
|
||||
return 1;
|
||||
|
||||
if (!ctxmith)
|
||||
ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
|
||||
|
||||
if (!ctxmith)
|
||||
return 1;
|
||||
|
||||
for (i=0; i < LPIPTBLSIZE; i++) {
|
||||
ctxmith[i] = (i & 0xF0) >> 4;
|
||||
ctxmitl[i] = 0x10 | (i & 0x0F);
|
||||
ctrecvh[i] = (i & 0x78) << 1;
|
||||
ctrecvl[i] = (i & 0x78) >> 3;
|
||||
}
|
||||
|
||||
for (i=0; i < LPIPTBLSIZE; i++) {
|
||||
txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
|
||||
txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
|
||||
trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
|
||||
trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an ioctl request.
|
||||
*/
|
||||
|
||||
static int
|
||||
lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
{
|
||||
struct lpt_softc *sc = lpdata[ifp->if_unit];
|
||||
struct ifaddr *ifa = (struct ifaddr *)data;
|
||||
struct ifreq *ifr = (struct ifreq *)data;
|
||||
u_char *ptr;
|
||||
int error;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case SIOCSIFDSTADDR:
|
||||
case SIOCAIFADDR:
|
||||
case SIOCSIFADDR:
|
||||
if (ifa->ifa_addr->sa_family != AF_INET)
|
||||
return EAFNOSUPPORT;
|
||||
|
||||
ifp->if_flags |= IFF_UP;
|
||||
/* FALLTHROUGH */
|
||||
case SIOCSIFFLAGS:
|
||||
if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) {
|
||||
|
||||
ppb_wctr(&sc->lp_dev, 0x00);
|
||||
ifp->if_flags &= ~IFF_RUNNING;
|
||||
|
||||
/* IFF_UP is not set, try to release the bus anyway */
|
||||
ppb_release_bus(&sc->lp_dev);
|
||||
break;
|
||||
}
|
||||
if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) {
|
||||
|
||||
/*
|
||||
* Try to allocate the ppbus as soon as possible
|
||||
* With ppbus allocation, interrupts are enabled
|
||||
* Now IFF_UP means that we own the bus
|
||||
*
|
||||
* XXX
|
||||
* Should the request be interruptible?
|
||||
*/
|
||||
if ((error = ppb_request_bus(&sc->lp_dev, PPB_WAIT|PPB_INTR)))
|
||||
return (error);
|
||||
|
||||
if (lpinittables()) {
|
||||
ppb_release_bus(&sc->lp_dev);
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
if (!sc->sc_ifbuf) {
|
||||
ppb_release_bus(&sc->lp_dev);
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
ppb_wctr(&sc->lp_dev, LPC_ENA);
|
||||
ifp->if_flags |= IFF_RUNNING;
|
||||
}
|
||||
break;
|
||||
|
||||
case SIOCSIFMTU:
|
||||
ptr = sc->sc_ifbuf;
|
||||
sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT);
|
||||
if (!sc->sc_ifbuf) {
|
||||
sc->sc_ifbuf = ptr;
|
||||
return ENOBUFS;
|
||||
}
|
||||
if (ptr)
|
||||
free(ptr,M_DEVBUF);
|
||||
sc->sc_if.if_mtu = ifr->ifr_mtu;
|
||||
break;
|
||||
|
||||
case SIOCGIFMTU:
|
||||
ifr->ifr_mtu = sc->sc_if.if_mtu;
|
||||
break;
|
||||
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
if (ifr == 0) {
|
||||
return EAFNOSUPPORT; /* XXX */
|
||||
}
|
||||
switch (ifr->ifr_addr.sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
break;
|
||||
|
||||
default:
|
||||
return EAFNOSUPPORT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
lprintf("LP:ioctl(0x%x)\n",cmd);
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline int
|
||||
clpoutbyte (u_char byte, int spin, struct ppb_device *dev)
|
||||
{
|
||||
ppb_wdtr(dev, ctxmitl[byte]);
|
||||
while (ppb_rstr(dev) & CLPIP_SHAKE)
|
||||
if (--spin == 0) {
|
||||
return 1;
|
||||
}
|
||||
ppb_wdtr(dev, ctxmith[byte]);
|
||||
while (!(ppb_rstr(dev) & CLPIP_SHAKE))
|
||||
if (--spin == 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline int
|
||||
clpinbyte (int spin, struct ppb_device *dev)
|
||||
{
|
||||
int c, cl;
|
||||
|
||||
while((ppb_rstr(dev) & CLPIP_SHAKE))
|
||||
if(!--spin) {
|
||||
return -1;
|
||||
}
|
||||
cl = ppb_rstr(dev);
|
||||
ppb_wdtr(dev, 0x10);
|
||||
|
||||
while(!(ppb_rstr(dev) & CLPIP_SHAKE))
|
||||
if(!--spin) {
|
||||
return -1;
|
||||
}
|
||||
c = ppb_rstr(dev);
|
||||
ppb_wdtr(dev, 0x00);
|
||||
|
||||
return (ctrecvl[cl] | ctrecvh[c]);
|
||||
}
|
||||
|
||||
static void
|
||||
lpintr (int unit)
|
||||
{
|
||||
struct lpt_softc *sc = lpdata[unit];
|
||||
int len, s, j;
|
||||
u_char *bp;
|
||||
u_char c, cl;
|
||||
struct mbuf *top;
|
||||
|
||||
s = splhigh();
|
||||
|
||||
if (sc->sc_if.if_flags & IFF_LINK0) {
|
||||
|
||||
/* Ack. the request */
|
||||
ppb_wdtr(&sc->lp_dev, 0x01);
|
||||
|
||||
/* Get the packet length */
|
||||
j = clpinbyte(LPMAXSPIN2, &sc->lp_dev);
|
||||
if (j == -1)
|
||||
goto err;
|
||||
len = j;
|
||||
j = clpinbyte(LPMAXSPIN2, &sc->lp_dev);
|
||||
if (j == -1)
|
||||
goto err;
|
||||
len = len + (j << 8);
|
||||
if (len > sc->sc_if.if_mtu + MLPIPHDRLEN)
|
||||
goto err;
|
||||
|
||||
bp = sc->sc_ifbuf;
|
||||
|
||||
while (len--) {
|
||||
j = clpinbyte(LPMAXSPIN2, &sc->lp_dev);
|
||||
if (j == -1) {
|
||||
goto err;
|
||||
}
|
||||
*bp++ = j;
|
||||
}
|
||||
/* Get and ignore checksum */
|
||||
j = clpinbyte(LPMAXSPIN2, &sc->lp_dev);
|
||||
if (j == -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
len = bp - sc->sc_ifbuf;
|
||||
if (len <= CLPIPHDRLEN)
|
||||
goto err;
|
||||
|
||||
sc->sc_iferrs = 0;
|
||||
|
||||
if (IF_QFULL(&ipintrq)) {
|
||||
lprintf("DROP");
|
||||
IF_DROP(&ipintrq);
|
||||
goto done;
|
||||
}
|
||||
len -= CLPIPHDRLEN;
|
||||
sc->sc_if.if_ipackets++;
|
||||
sc->sc_if.if_ibytes += len;
|
||||
top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0);
|
||||
if (top) {
|
||||
IF_ENQUEUE(&ipintrq, top);
|
||||
schednetisr(NETISR_IP);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
while ((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE)) {
|
||||
len = sc->sc_if.if_mtu + LPIPHDRLEN;
|
||||
bp = sc->sc_ifbuf;
|
||||
while (len--) {
|
||||
|
||||
cl = ppb_rstr(&sc->lp_dev);
|
||||
ppb_wdtr(&sc->lp_dev, 8);
|
||||
|
||||
j = LPMAXSPIN2;
|
||||
while((ppb_rstr(&sc->lp_dev) & LPIP_SHAKE))
|
||||
if(!--j) goto err;
|
||||
|
||||
c = ppb_rstr(&sc->lp_dev);
|
||||
ppb_wdtr(&sc->lp_dev, 0);
|
||||
|
||||
*bp++= trecvh[cl] | trecvl[c];
|
||||
|
||||
j = LPMAXSPIN2;
|
||||
while (!((cl=ppb_rstr(&sc->lp_dev)) & LPIP_SHAKE)) {
|
||||
if (cl != c &&
|
||||
(((cl = ppb_rstr(&sc->lp_dev)) ^ 0xb8) & 0xf8) ==
|
||||
(c & 0xf8))
|
||||
goto end;
|
||||
if (!--j) goto err;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
len = bp - sc->sc_ifbuf;
|
||||
if (len <= LPIPHDRLEN)
|
||||
goto err;
|
||||
|
||||
sc->sc_iferrs = 0;
|
||||
|
||||
if (IF_QFULL(&ipintrq)) {
|
||||
lprintf("DROP");
|
||||
IF_DROP(&ipintrq);
|
||||
goto done;
|
||||
}
|
||||
#if NBPFILTER > 0
|
||||
if (sc->sc_if.if_bpf) {
|
||||
bpf_tap(&sc->sc_if, sc->sc_ifbuf, len);
|
||||
}
|
||||
#endif
|
||||
len -= LPIPHDRLEN;
|
||||
sc->sc_if.if_ipackets++;
|
||||
sc->sc_if.if_ibytes += len;
|
||||
top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0);
|
||||
if (top) {
|
||||
IF_ENQUEUE(&ipintrq, top);
|
||||
schednetisr(NETISR_IP);
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
|
||||
err:
|
||||
ppb_wdtr(&sc->lp_dev, 0);
|
||||
lprintf("R");
|
||||
sc->sc_if.if_ierrors++;
|
||||
sc->sc_iferrs++;
|
||||
|
||||
/*
|
||||
* We are not able to send receive anything for now,
|
||||
* so stop wasting our time
|
||||
*/
|
||||
if (sc->sc_iferrs > LPMAXERRS) {
|
||||
printf("lp%d: Too many errors, Going off-line.\n", unit);
|
||||
ppb_wctr(&sc->lp_dev, 0x00);
|
||||
sc->sc_if.if_flags &= ~IFF_RUNNING;
|
||||
sc->sc_iferrs=0;
|
||||
}
|
||||
|
||||
done:
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
static __inline int
|
||||
lpoutbyte (u_char byte, int spin, struct ppb_device *dev)
|
||||
{
|
||||
ppb_wdtr(dev, txmith[byte]);
|
||||
while (!(ppb_rstr(dev) & LPIP_SHAKE))
|
||||
if (--spin == 0)
|
||||
return 1;
|
||||
ppb_wdtr(dev, txmitl[byte]);
|
||||
while (ppb_rstr(dev) & LPIP_SHAKE)
|
||||
if (--spin == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lpoutput (struct ifnet *ifp, struct mbuf *m,
|
||||
struct sockaddr *dst, struct rtentry *rt)
|
||||
{
|
||||
struct lpt_softc *sc = lpdata[ifp->if_unit];
|
||||
int s, err;
|
||||
struct mbuf *mm;
|
||||
u_char *cp = "\0\0";
|
||||
u_char chksum = 0;
|
||||
int count = 0;
|
||||
int i;
|
||||
int spin;
|
||||
|
||||
/* We need a sensible value if we abort */
|
||||
cp++;
|
||||
ifp->if_flags |= IFF_RUNNING;
|
||||
|
||||
err = 1; /* assume we're aborting because of an error */
|
||||
|
||||
s = splhigh();
|
||||
|
||||
/* Suspend (on laptops) or receive-errors might have taken us offline */
|
||||
ppb_wctr(&sc->lp_dev, LPC_ENA);
|
||||
|
||||
if (ifp->if_flags & IFF_LINK0) {
|
||||
|
||||
if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) {
|
||||
lprintf("&");
|
||||
lpintr(ifp->if_unit);
|
||||
}
|
||||
|
||||
/* Alert other end to pending packet */
|
||||
spin = LPMAXSPIN1;
|
||||
ppb_wdtr(&sc->lp_dev, 0x08);
|
||||
while ((ppb_rstr(&sc->lp_dev) & 0x08) == 0)
|
||||
if (--spin == 0) {
|
||||
goto nend;
|
||||
}
|
||||
|
||||
/* Calculate length of packet, then send that */
|
||||
|
||||
count += 14; /* Ethernet header len */
|
||||
|
||||
mm = m;
|
||||
for (mm = m; mm; mm = mm->m_next) {
|
||||
count += mm->m_len;
|
||||
}
|
||||
if (clpoutbyte(count & 0xFF, LPMAXSPIN1, &sc->lp_dev))
|
||||
goto nend;
|
||||
if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, &sc->lp_dev))
|
||||
goto nend;
|
||||
|
||||
/* Send dummy ethernet header */
|
||||
for (i = 0; i < 12; i++) {
|
||||
if (clpoutbyte(i, LPMAXSPIN1, &sc->lp_dev))
|
||||
goto nend;
|
||||
chksum += i;
|
||||
}
|
||||
|
||||
if (clpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev))
|
||||
goto nend;
|
||||
if (clpoutbyte(0x00, LPMAXSPIN1, &sc->lp_dev))
|
||||
goto nend;
|
||||
chksum += 0x08 + 0x00; /* Add into checksum */
|
||||
|
||||
mm = m;
|
||||
do {
|
||||
cp = mtod(mm, u_char *);
|
||||
while (mm->m_len--) {
|
||||
chksum += *cp;
|
||||
if (clpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev))
|
||||
goto nend;
|
||||
}
|
||||
} while ((mm = mm->m_next));
|
||||
|
||||
/* Send checksum */
|
||||
if (clpoutbyte(chksum, LPMAXSPIN2, &sc->lp_dev))
|
||||
goto nend;
|
||||
|
||||
/* Go quiescent */
|
||||
ppb_wdtr(&sc->lp_dev, 0);
|
||||
|
||||
err = 0; /* No errors */
|
||||
|
||||
nend:
|
||||
if (err) { /* if we didn't timeout... */
|
||||
ifp->if_oerrors++;
|
||||
lprintf("X");
|
||||
} else {
|
||||
ifp->if_opackets++;
|
||||
ifp->if_obytes += m->m_pkthdr.len;
|
||||
}
|
||||
|
||||
m_freem(m);
|
||||
|
||||
if (!(ppb_rstr(&sc->lp_dev) & CLPIP_SHAKE)) {
|
||||
lprintf("^");
|
||||
lpintr(ifp->if_unit);
|
||||
}
|
||||
(void) splx(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) {
|
||||
lprintf("&");
|
||||
lpintr(ifp->if_unit);
|
||||
}
|
||||
|
||||
if (lpoutbyte(0x08, LPMAXSPIN1, &sc->lp_dev))
|
||||
goto end;
|
||||
if (lpoutbyte(0x00, LPMAXSPIN2, &sc->lp_dev))
|
||||
goto end;
|
||||
|
||||
mm = m;
|
||||
do {
|
||||
cp = mtod(mm,u_char *);
|
||||
while (mm->m_len--)
|
||||
if (lpoutbyte(*cp++, LPMAXSPIN2, &sc->lp_dev))
|
||||
goto end;
|
||||
} while ((mm = mm->m_next));
|
||||
|
||||
err = 0; /* no errors were encountered */
|
||||
|
||||
end:
|
||||
--cp;
|
||||
ppb_wdtr(&sc->lp_dev, txmitl[*cp] ^ 0x17);
|
||||
|
||||
if (err) { /* if we didn't timeout... */
|
||||
ifp->if_oerrors++;
|
||||
lprintf("X");
|
||||
} else {
|
||||
ifp->if_opackets++;
|
||||
ifp->if_obytes += m->m_pkthdr.len;
|
||||
#if NBPFILTER > 0
|
||||
if (ifp->if_bpf) {
|
||||
/*
|
||||
* We need to prepend the packet type as
|
||||
* a two byte field. Cons up a dummy header
|
||||
* to pacify bpf. This is safe because bpf
|
||||
* will only read from the mbuf (i.e., it won't
|
||||
* try to free it or keep a pointer to it).
|
||||
*/
|
||||
struct mbuf m0;
|
||||
u_short hdr = 0x800;
|
||||
|
||||
m0.m_next = m;
|
||||
m0.m_len = 2;
|
||||
m0.m_data = (char *)&hdr;
|
||||
|
||||
bpf_mtap(ifp, &m0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
m_freem(m);
|
||||
|
||||
if (ppb_rstr(&sc->lp_dev) & LPIP_SHAKE) {
|
||||
lprintf("^");
|
||||
lpintr(ifp->if_unit);
|
||||
}
|
||||
|
||||
(void) splx(s);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
*
|
||||
* from: unknown origin, 386BSD 0.1
|
||||
* From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
|
||||
* $Id: nlpt.c,v 1.7 1998/01/24 02:54:05 eivind Exp $
|
||||
* $Id: nlpt.c,v 1.8 1998/06/07 17:09:48 dfr Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
@ -134,7 +134,7 @@ DATA_SET(ppbdriver_set, nlptdriver);
|
|||
#define OBUSY (1<<3) /* printer is busy doing output */
|
||||
#define LPTOUT (1<<4) /* timeout while not selected */
|
||||
#define TOUT (1<<5) /* timeout while not selected */
|
||||
#define INIT (1<<6) /* waiting to initialize for open */
|
||||
#define LPTINIT (1<<6) /* waiting to initialize for open */
|
||||
#define INTERRUPTED (1<<7) /* write call was interrupted */
|
||||
|
||||
#define HAVEBUS (1<<8) /* the driver owns the bus */
|
||||
|
|
@ -168,15 +168,25 @@ static struct cdevsw nlpt_cdevsw =
|
|||
static int
|
||||
lpt_request_ppbus(struct lpt_data *sc, int how)
|
||||
{
|
||||
sc->sc_state |= HAVEBUS;
|
||||
return (ppb_request_bus(&sc->lpt_dev, how));
|
||||
int error;
|
||||
|
||||
/* we have the bus only if the request succeded */
|
||||
if ((error = ppb_request_bus(&sc->lpt_dev, how)) == 0)
|
||||
sc->sc_state |= HAVEBUS;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
lpt_release_ppbus(struct lpt_data *sc)
|
||||
{
|
||||
sc->sc_state &= ~HAVEBUS;
|
||||
return (ppb_release_bus(&sc->lpt_dev));
|
||||
int error;
|
||||
|
||||
/* we do not have the bus only if the request succeded */
|
||||
if ((error = ppb_release_bus(&sc->lpt_dev)) == 0)
|
||||
sc->sc_state &= ~HAVEBUS;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -316,6 +326,7 @@ nlptprobe(struct ppb_data *ppb)
|
|||
* ppbus dependent initialisation.
|
||||
*/
|
||||
sc->lpt_dev.id_unit = sc->lpt_unit;
|
||||
sc->lpt_dev.name = nlptdriver.name;
|
||||
sc->lpt_dev.ppb = ppb;
|
||||
sc->lpt_dev.intr = nlptintr;
|
||||
|
||||
|
|
@ -401,19 +412,6 @@ nlptout(void *arg)
|
|||
* Avoid possible hangs do to missed interrupts
|
||||
*/
|
||||
if (sc->sc_xfercnt) {
|
||||
/* if we cannot allocate the bus NOW, retry later */
|
||||
if ((sc->sc_state & HAVEBUS) == 0 &&
|
||||
lpt_request_ppbus (sc, PPB_DONTWAIT)) {
|
||||
|
||||
sc->sc_backoff++;
|
||||
if (sc->sc_backoff > hz/LPTOUTMAX)
|
||||
sc->sc_backoff =
|
||||
sc->sc_backoff > hz/LPTOUTMAX;
|
||||
timeout(nlptout, (caddr_t)sc,
|
||||
sc->sc_backoff);
|
||||
return;
|
||||
}
|
||||
|
||||
pl = spltty();
|
||||
nlptintr(sc->lpt_unit);
|
||||
splx(pl);
|
||||
|
|
@ -447,7 +445,7 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
|
|||
nlprintf(LPT_NAME ": still open %x\n", sc->sc_state);
|
||||
return(EBUSY);
|
||||
} else
|
||||
sc->sc_state |= INIT;
|
||||
sc->sc_state |= LPTINIT;
|
||||
|
||||
sc->sc_flags = LPTFLAGS(minor(dev));
|
||||
|
||||
|
|
@ -457,7 +455,9 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
|
|||
return(0);
|
||||
}
|
||||
|
||||
if (lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
/* request the ppbus only if we don't have it already */
|
||||
if ((sc->sc_state & HAVEBUS) == 0 &&
|
||||
lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
return (EINTR);
|
||||
|
||||
s = spltty();
|
||||
|
|
@ -523,7 +523,7 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
|
|||
sc->sc_xfercnt = 0;
|
||||
splx(s);
|
||||
|
||||
/* release the bus, nlptout() will try to allocate it later */
|
||||
/* release the ppbus */
|
||||
lpt_release_ppbus(sc);
|
||||
|
||||
/* only use timeout if using interrupt */
|
||||
|
|
@ -572,9 +572,10 @@ nlptclose(dev_t dev, int flags, int fmt, struct proc *p)
|
|||
ppb_wctr(&sc->lpt_dev, LPC_NINIT);
|
||||
brelse(sc->sc_inbuf);
|
||||
|
||||
end_close:
|
||||
/* release the bus anyway */
|
||||
lpt_release_ppbus(sc);
|
||||
|
||||
end_close:
|
||||
sc->sc_state = 0;
|
||||
sc->sc_xfercnt = 0;
|
||||
nlprintf("closed.\n");
|
||||
|
|
@ -660,7 +661,9 @@ nlptwrite(dev_t dev, struct uio *uio, int ioflag)
|
|||
return(EPERM);
|
||||
}
|
||||
|
||||
if (lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
/* request the ppbus only if we don't have it already */
|
||||
if ((sc->sc_state & HAVEBUS) == 0 &&
|
||||
lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
return (EINTR);
|
||||
|
||||
sc->sc_state &= ~INTERRUPTED;
|
||||
|
|
@ -691,12 +694,15 @@ nlptwrite(dev_t dev, struct uio *uio, int ioflag)
|
|||
nlprintf("p");
|
||||
|
||||
err = nlpt_pushbytes(sc);
|
||||
lpt_release_ppbus(sc);
|
||||
|
||||
if (err)
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
/* we have not been interrupted, release the ppbus */
|
||||
lpt_release_ppbus(sc);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
|
@ -713,6 +719,10 @@ nlptintr(int unit)
|
|||
struct lpt_data *sc = lptdata[unit];
|
||||
int sts;
|
||||
int i;
|
||||
|
||||
/* we must own the bus to use it */
|
||||
if ((sc->sc_state & HAVEBUS) == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Is printer online and ready for output?
|
||||
|
|
@ -744,7 +754,6 @@ nlptintr(int unit)
|
|||
* Wakeup is not done if write call was interrupted.
|
||||
*/
|
||||
sc->sc_state &= ~OBUSY;
|
||||
lpt_release_ppbus(sc);
|
||||
|
||||
if(!(sc->sc_state & INTERRUPTED))
|
||||
wakeup((caddr_t)sc);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_1284.c,v 1.2 1997/09/01 00:51:44 bde Exp $
|
||||
* $Id: ppb_1284.c,v 1.3 1998/01/31 07:23:06 eivind Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -38,41 +38,79 @@
|
|||
#include <dev/ppbus/ppb_1284.h>
|
||||
|
||||
/*
|
||||
* nibble_1284_wait()
|
||||
* do_1284_wait()
|
||||
*
|
||||
* Wait for the peripherial up to 40ms
|
||||
*/
|
||||
int
|
||||
nibble_1284_wait(struct ppb_device *dev, char mask, char status)
|
||||
do_1284_wait(struct ppb_device *dev, char mask, char status)
|
||||
{
|
||||
int i;
|
||||
char r;
|
||||
|
||||
/* try up to 5ms */
|
||||
for (i = 0; i < 20; i++) {
|
||||
r = ppb_rstr(dev);
|
||||
DELAY(25);
|
||||
if ((r & mask) == status)
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (ppb_poll_device(dev, 4, mask, status, PPB_NOINTR));
|
||||
}
|
||||
|
||||
#define nibble2char(s) (((s & ~nACK) >> 3) | (~s & nBUSY) >> 4)
|
||||
|
||||
/*
|
||||
* byte_1284_inbyte()
|
||||
*
|
||||
* Read 1 byte in BYTE mode
|
||||
*/
|
||||
int
|
||||
byte_1284_inbyte(struct ppb_device *dev, char *buffer)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* notify the peripherial to put data on the lines */
|
||||
ppb_wctr(dev, PCD | AUTOFEED | nSTROBE | nINIT | nSELECTIN);
|
||||
|
||||
/* wait for valid byte signal */
|
||||
if ((error = do_1284_wait(dev, nACK, 0)))
|
||||
return (error);
|
||||
|
||||
/* fetch data */
|
||||
*buffer = ppb_rdtr(dev);
|
||||
|
||||
/* indicate that data has been received, not ready for another */
|
||||
ppb_wctr(dev, PCD | nAUTOFEED | nSTROBE | nINIT | nSELECTIN);
|
||||
|
||||
/* wait peripherial's acknowledgement */
|
||||
if ((error = do_1284_wait(dev, nACK, nACK)))
|
||||
return (error);
|
||||
|
||||
/* acknowledge the peripherial */
|
||||
ppb_wctr(dev, PCD | nAUTOFEED | STROBE | nINIT | nSELECTIN);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* nibble_1284_inbyte()
|
||||
*
|
||||
* Read data in NIBBLE mode
|
||||
* Read 1 byte in NIBBLE mode
|
||||
*/
|
||||
int
|
||||
nibble_1284_inbyte(struct ppb_device *dev, char *buffer)
|
||||
{
|
||||
char nibble[2], r;
|
||||
char nibble[2];
|
||||
int i, error;
|
||||
|
||||
r = ppb_rctr(dev);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* ready to take data (nAUTO low) */
|
||||
ppb_wctr(dev, r | AUTOFEED);
|
||||
ppb_wctr(dev, AUTOFEED | nSTROBE | nINIT | nSELECTIN);
|
||||
|
||||
if ((error = nibble_1284_wait(dev, nACK, 0))) {
|
||||
ppb_wctr(dev, r);
|
||||
if ((error = do_1284_wait(dev, nACK, 0)))
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* read nibble */
|
||||
nibble[i] = ppb_rstr(dev);
|
||||
|
|
@ -82,13 +120,11 @@ nibble_1284_inbyte(struct ppb_device *dev, char *buffer)
|
|||
#endif
|
||||
|
||||
/* ack, not ready for another nibble */
|
||||
ppb_wctr(dev, r & ~AUTOFEED);
|
||||
ppb_wctr(dev, nAUTOFEED | nSTROBE | nINIT | nSELECTIN);
|
||||
|
||||
/* wait ack from peripherial */
|
||||
if ((error = nibble_1284_wait(dev, nACK, nACK))) {
|
||||
ppb_wctr(dev, r);
|
||||
if ((error = do_1284_wait(dev, nACK, nACK)))
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
*buffer = ((nibble2char(nibble[1]) << 4) & 0xf0) |
|
||||
|
|
@ -112,11 +148,11 @@ nibble_1284_sync(struct ppb_device *dev)
|
|||
ctr = ppb_rctr(dev);
|
||||
|
||||
ppb_wctr(dev, (ctr & ~AUTOFEED) | SELECTIN);
|
||||
if (nibble_1284_wait(dev, nACK, 0))
|
||||
if (do_1284_wait(dev, nACK, 0))
|
||||
return;
|
||||
|
||||
ppb_wctr(dev, ctr | AUTOFEED);
|
||||
nibble_1284_wait(dev, nACK, nACK);
|
||||
do_1284_wait(dev, nACK, nACK);
|
||||
|
||||
ppb_wctr(dev, (ctr & ~AUTOFEED) | SELECTIN);
|
||||
|
||||
|
|
@ -140,7 +176,7 @@ nibble_1284_mode(struct ppb_device *dev, int mode)
|
|||
DELAY(5);
|
||||
|
||||
ppb_wctr(dev, (ctrl & ~SELECTIN) | AUTOFEED);
|
||||
if ((error = nibble_1284_wait(dev, nACK | ERROR | SELECT | nFAULT,
|
||||
if ((error = do_1284_wait(dev, nACK | ERROR | SELECT | nFAULT,
|
||||
ERROR | SELECT | nFAULT))) {
|
||||
ppb_wctr(dev, ctrl);
|
||||
return (error);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
* $Id: ppb_1284.h,v 1.1 1997/08/16 14:05:33 msmith Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __1284_H
|
||||
|
|
@ -32,9 +32,12 @@
|
|||
#define NIBBLE_1284_NORMAL 0
|
||||
#define NIBBLE_1284_REQUEST_ID 4
|
||||
|
||||
extern void nibble_1284_sync(struct ppb_device *);
|
||||
extern int do_1284_wait(struct ppb_device *, char, char);
|
||||
|
||||
extern int byte_1284_inbyte(struct ppb_device *, char *);
|
||||
|
||||
extern int nibble_1284_inbyte(struct ppb_device *, char *);
|
||||
extern int nibble_1284_wait(struct ppb_device *, char, char);
|
||||
extern void nibble_1284_sync(struct ppb_device *);
|
||||
extern int nibble_1284_mode(struct ppb_device *, int);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Nicolas Souchu
|
||||
* Copyright (c) 1997, 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_base.c,v 1.2 1997/08/28 10:15:12 msmith Exp $
|
||||
* $Id: ppb_base.c,v 1.3 1997/09/01 00:51:45 bde Exp $
|
||||
*
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
|
|
@ -97,10 +97,30 @@ ppb_poll_device(struct ppb_device *dev, int max,
|
|||
return (EWOULDBLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_set_mode()
|
||||
*
|
||||
* Set the operating mode of the chipset
|
||||
*/
|
||||
int
|
||||
ppb_set_mode(struct ppb_device *dev, int mode)
|
||||
{
|
||||
struct ppb_data *ppb = dev->ppb;
|
||||
int old_mode = ppb_get_mode(dev);
|
||||
|
||||
if ((*ppb->ppb_link->adapter->setmode)(dev->id_unit, mode))
|
||||
return (-1);
|
||||
|
||||
/* XXX yet device mode = ppbus mode = chipset mode */
|
||||
dev->mode = ppb->mode = mode;
|
||||
|
||||
return (old_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_reset_epp_timeout()
|
||||
*
|
||||
* Reset the EPP timeout bit in the status register.
|
||||
* Reset the EPP timeout bit in the status register
|
||||
*/
|
||||
int
|
||||
ppb_reset_epp_timeout(struct ppb_device *dev)
|
||||
|
|
@ -118,7 +138,7 @@ ppb_reset_epp_timeout(struct ppb_device *dev)
|
|||
/*
|
||||
* ppb_ecp_sync()
|
||||
*
|
||||
* Wait for the ECP FIFO to be empty.
|
||||
* Wait for the ECP FIFO to be empty
|
||||
*/
|
||||
int
|
||||
ppb_ecp_sync(struct ppb_device *dev)
|
||||
|
|
@ -133,43 +153,10 @@ ppb_ecp_sync(struct ppb_device *dev)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_get_mode()
|
||||
*
|
||||
* Read the mode (SPP, EPP...) of the chipset.
|
||||
*/
|
||||
int
|
||||
ppb_get_mode(struct ppb_device *dev)
|
||||
{
|
||||
return (dev->ppb->ppb_link->mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_get_epp_protocol()
|
||||
*
|
||||
* Read the EPP protocol (1.9 or 1.7).
|
||||
*/
|
||||
int
|
||||
ppb_get_epp_protocol(struct ppb_device *dev)
|
||||
{
|
||||
return (dev->ppb->ppb_link->epp_protocol);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_get_irq()
|
||||
*
|
||||
* Return the irq, 0 if none.
|
||||
*/
|
||||
int
|
||||
ppb_get_irq(struct ppb_device *dev)
|
||||
{
|
||||
return (dev->ppb->ppb_link->id_irq);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_get_status()
|
||||
*
|
||||
* Read the status register and update the status info.
|
||||
* Read the status register and update the status info
|
||||
*/
|
||||
int
|
||||
ppb_get_status(struct ppb_device *dev, struct ppb_status *status)
|
||||
|
|
|
|||
326
sys/dev/ppbus/ppb_msq.c
Normal file
326
sys/dev/ppbus/ppb_msq.c
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_msq.c,v 1.1.2.4 1998/06/16 23:35:51 son Exp $
|
||||
*
|
||||
*/
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
|
||||
/* msq index (see PPB_MAX_XFER)
|
||||
* These are device modes
|
||||
*/
|
||||
#define COMPAT_MSQ 0x0
|
||||
#define NIBBLE_MSQ 0x1
|
||||
#define PS2_MSQ 0x2
|
||||
#define EPP17_MSQ 0x3
|
||||
#define EPP19_MSQ 0x4
|
||||
#define ECP_MSQ 0x5
|
||||
|
||||
/*
|
||||
* Device mode to submsq conversion
|
||||
*/
|
||||
static struct ppb_xfer *
|
||||
mode2xfer(struct ppb_device *dev, int opcode)
|
||||
{
|
||||
int index, epp;
|
||||
struct ppb_xfer *table;
|
||||
|
||||
switch (opcode) {
|
||||
case MS_OP_GET:
|
||||
table = dev->get_xfer;
|
||||
break;
|
||||
|
||||
case MS_OP_PUT:
|
||||
table = dev->put_xfer;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unknown opcode (%d)", __FUNCTION__, opcode);
|
||||
}
|
||||
|
||||
/* retrieve the device operating mode */
|
||||
switch (ppb_get_mode(dev)) {
|
||||
case PPB_COMPATIBLE:
|
||||
index = COMPAT_MSQ;
|
||||
break;
|
||||
case PPB_NIBBLE:
|
||||
index = NIBBLE_MSQ;
|
||||
break;
|
||||
case PPB_PS2:
|
||||
index = PS2_MSQ;
|
||||
break;
|
||||
case PPB_EPP:
|
||||
switch ((epp = ppb_get_epp_protocol(dev))) {
|
||||
case EPP_1_7:
|
||||
index = EPP17_MSQ;
|
||||
break;
|
||||
case EPP_1_9:
|
||||
index = EPP19_MSQ;
|
||||
break;
|
||||
default:
|
||||
panic("%s: unknown EPP protocol (0x%x)!", __FUNCTION__,
|
||||
epp);
|
||||
}
|
||||
break;
|
||||
case PPB_ECP:
|
||||
index = ECP_MSQ;
|
||||
break;
|
||||
default:
|
||||
panic("%s: unknown mode (%d)", __FUNCTION__, dev->mode);
|
||||
}
|
||||
|
||||
return (&table[index]);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_MS_init()
|
||||
*
|
||||
* Initialize device dependent submicrosequence of the current mode
|
||||
*
|
||||
*/
|
||||
int
|
||||
ppb_MS_init(struct ppb_device *dev, struct ppb_microseq *loop, int opcode)
|
||||
{
|
||||
struct ppb_xfer *xfer = mode2xfer(dev, opcode);
|
||||
|
||||
xfer->loop = loop;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_MS_exec()
|
||||
*
|
||||
* Execute any microsequence opcode - expensive
|
||||
*
|
||||
*/
|
||||
int
|
||||
ppb_MS_exec(struct ppb_device *dev, int opcode, union ppb_insarg param1,
|
||||
union ppb_insarg param2, union ppb_insarg param3, int *ret)
|
||||
{
|
||||
struct ppb_microseq msq[] = {
|
||||
{ MS_UNKNOWN, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/* initialize the corresponding microseq */
|
||||
msq[0].opcode = opcode;
|
||||
msq[0].arg[0] = param1;
|
||||
msq[0].arg[1] = param2;
|
||||
msq[0].arg[2] = param3;
|
||||
|
||||
/* execute the microseq */
|
||||
return (ppb_MS_microseq(dev, msq, ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_MS_loop()
|
||||
*
|
||||
* Execute a microseq loop
|
||||
*
|
||||
*/
|
||||
int
|
||||
ppb_MS_loop(struct ppb_device *dev, struct ppb_microseq *prolog,
|
||||
struct ppb_microseq *body, struct ppb_microseq *epilog,
|
||||
int iter, int *ret)
|
||||
{
|
||||
struct ppb_microseq loop_microseq[] = {
|
||||
MS_CALL(NULL), /* execute prolog */
|
||||
|
||||
MS_SET(MS_UNKNOWN), /* set size of transfer */
|
||||
/* loop: */
|
||||
MS_CALL(NULL), /* execute body */
|
||||
MS_DBRA(-1 /* loop: */),
|
||||
|
||||
MS_CALL(NULL), /* execute epilog */
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/* initialize the structure */
|
||||
loop_microseq[0].arg[0].p = (void *)prolog;
|
||||
loop_microseq[1].arg[0].i = iter;
|
||||
loop_microseq[2].arg[0].p = (void *)body;
|
||||
loop_microseq[4].arg[0].p = (void *)epilog;
|
||||
|
||||
/* execute the loop */
|
||||
return (ppb_MS_microseq(dev, loop_microseq, ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_MS_init_msq()
|
||||
*
|
||||
* Initialize a microsequence - see macros in ppb_msq.h
|
||||
*
|
||||
*/
|
||||
int
|
||||
ppb_MS_init_msq(struct ppb_microseq *msq, int nbparam, ...)
|
||||
{
|
||||
int i;
|
||||
int param, ins, arg, type;
|
||||
va_list p_list = 0;
|
||||
|
||||
va_start(p_list, nbparam);
|
||||
|
||||
for (i=0; i<nbparam; i++) {
|
||||
/* retrieve the parameter descriptor */
|
||||
param = va_arg(p_list, int);
|
||||
|
||||
ins = MS_INS(param);
|
||||
arg = MS_ARG(param);
|
||||
type = MS_TYP(param);
|
||||
|
||||
/* check the instruction position */
|
||||
if (arg >= PPB_MS_MAXARGS)
|
||||
panic("%s: parameter out of range (0x%x)!",
|
||||
__FUNCTION__, param);
|
||||
|
||||
#if 0
|
||||
printf("%s: param = %d, ins = %d, arg = %d, type = %d\n",
|
||||
__FUNCTION__, param, ins, arg, type);
|
||||
#endif
|
||||
|
||||
/* properly cast the parameter */
|
||||
switch (type) {
|
||||
case MS_TYP_INT:
|
||||
msq[ins].arg[arg].i = va_arg(p_list, int);
|
||||
break;
|
||||
|
||||
case MS_TYP_CHA:
|
||||
msq[ins].arg[arg].c = va_arg(p_list, char);
|
||||
break;
|
||||
|
||||
case MS_TYP_PTR:
|
||||
msq[ins].arg[arg].p = va_arg(p_list, void *);
|
||||
break;
|
||||
|
||||
case MS_TYP_FUN:
|
||||
msq[ins].arg[arg].f = va_arg(p_list, void *);
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unknown parameter (0x%x)!", __FUNCTION__,
|
||||
param);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_MS_microseq()
|
||||
*
|
||||
* Interprete a microsequence. Some microinstructions are executed at adapter
|
||||
* level to avoid function call overhead between ppbus and the adapter
|
||||
*/
|
||||
int
|
||||
ppb_MS_microseq(struct ppb_device *dev, struct ppb_microseq *msq, int *ret)
|
||||
{
|
||||
struct ppb_data *ppb = dev->ppb;
|
||||
struct ppb_microseq *mi; /* current microinstruction */
|
||||
int msq_index;
|
||||
int pc, error;
|
||||
|
||||
struct ppb_xfer *xfer;
|
||||
|
||||
/* microsequence executed to initialize the transfer */
|
||||
struct ppb_microseq initxfer[] = {
|
||||
MS_PTR(MS_UNKNOWN), /* set ptr to buffer */
|
||||
MS_SET(MS_UNKNOWN), /* set transfer size */
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
if (ppb->ppb_owner != dev)
|
||||
return (EACCES);
|
||||
|
||||
#define INCR_PC (pc ++)
|
||||
|
||||
pc = 0;
|
||||
for (;;) {
|
||||
|
||||
/* retrieve the next microinstruction to execute */
|
||||
mi = &msq[pc];
|
||||
|
||||
switch (mi->opcode) {
|
||||
case MS_OP_PUT:
|
||||
case MS_OP_GET:
|
||||
|
||||
/* attempt to choose the best mode for the device */
|
||||
xfer = mode2xfer(dev, mi->opcode);
|
||||
|
||||
/* figure out if we should use ieee1284 code */
|
||||
if (!xfer->loop)
|
||||
panic("%s: IEEE1284 code not supported",
|
||||
__FUNCTION__);
|
||||
|
||||
/* XXX should use ppb_MS_init_msq() */
|
||||
initxfer[0].arg[0].p = mi->arg[0].p;
|
||||
initxfer[1].arg[0].i = mi->arg[1].i;
|
||||
|
||||
/* initialize transfer */
|
||||
ppb_MS_microseq(dev, initxfer, &error);
|
||||
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
/* the xfer microsequence should not contain any
|
||||
* MS_OP_PUT or MS_OP_GET!
|
||||
*/
|
||||
ppb_MS_microseq(dev, xfer->loop, &error);
|
||||
|
||||
if (error)
|
||||
goto error;
|
||||
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RET:
|
||||
*ret = mi->arg[0].i; /* return code */
|
||||
return (0);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* executing microinstructions at ppc level is
|
||||
* faster. This is the default if the microinstr
|
||||
* is unknown here
|
||||
*/
|
||||
if ((error = ppb->ppb_link->adapter->exec_microseq(
|
||||
dev->id_unit, msq, &pc)))
|
||||
return (error);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
error:
|
||||
*ret = error;
|
||||
return (0);
|
||||
}
|
||||
|
||||
190
sys/dev/ppbus/ppb_msq.h
Normal file
190
sys/dev/ppbus/ppb_msq.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_msq.h,v 1.1.2.6 1998/06/17 00:37:12 son Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPB_MSQ_H
|
||||
#define __PPB_MSQ_H
|
||||
|
||||
/*
|
||||
* Basic definitions
|
||||
*/
|
||||
|
||||
/* microsequence parameter descriptor */
|
||||
#define MS_INS_MASK 0x00ff /* mask to retrieve the instruction position */
|
||||
#define MS_ARG_MASK 0x0f00 /* mask to retrieve the argument number */
|
||||
#define MS_TYP_MASK 0xf000 /* mask to retrieve the type of the param */
|
||||
|
||||
/* offset of each mask (see above) */
|
||||
#define MS_INS_OFFSET 0
|
||||
#define MS_ARG_OFFSET 8
|
||||
#define MS_TYP_OFFSET 12
|
||||
|
||||
/* list of parameter types */
|
||||
#define MS_TYP_INT 0x0 /* integer */
|
||||
#define MS_TYP_CHA 0x1 /* character */
|
||||
#define MS_TYP_PTR 0x2 /* void pointer */
|
||||
#define MS_TYP_FUN 0x3 /* function pointer */
|
||||
|
||||
#define MS_PARAM(ins,arg,typ) \
|
||||
(((ins<<MS_INS_OFFSET) & MS_INS_MASK) | \
|
||||
((arg<<MS_ARG_OFFSET) & MS_ARG_MASK) | \
|
||||
((typ<<MS_TYP_OFFSET) & MS_TYP_MASK))
|
||||
|
||||
#define MS_INS(param) ((param & MS_INS_MASK) >> MS_INS_OFFSET)
|
||||
#define MS_ARG(param) ((param & MS_ARG_MASK) >> MS_ARG_OFFSET)
|
||||
#define MS_TYP(param) ((param & MS_TYP_MASK) >> MS_TYP_OFFSET)
|
||||
|
||||
/* microsequence opcodes - do not change! */
|
||||
#define MS_OP_GET 0 /* get <ptr>, <len> */
|
||||
#define MS_OP_PUT 1 /* put <ptr>, <len> */
|
||||
|
||||
#define MS_OP_RFETCH 2 /* rfetch <reg>, <mask>, <ptr> */
|
||||
#define MS_OP_RSET 3 /* rset <reg>, <mask>, <mask> */
|
||||
#define MS_OP_RASSERT 4 /* rassert <reg>, <mask> */
|
||||
#define MS_OP_DELAY 5 /* delay <val> */
|
||||
#define MS_OP_SET 6 /* set <val> */
|
||||
#define MS_OP_DBRA 7 /* dbra <offset> */
|
||||
#define MS_OP_BRSET 8 /* brset <mask>, <offset> */
|
||||
#define MS_OP_BRCLEAR 9 /* brclear <mask>, <offset> */
|
||||
#define MS_OP_RET 10 /* ret <retcode> */
|
||||
#define MS_OP_C_CALL 11 /* c_call <function>, <parameter> */
|
||||
#define MS_OP_PTR 12 /* ptr <pointer> */
|
||||
#define MS_RESERVED_1 13 /* reserved */
|
||||
#define MS_RESERVED_2 14 /* reserved */
|
||||
#define MS_OP_SUBRET 15 /* subret <code> */
|
||||
#define MS_OP_CALL 16 /* call <microsequence> */
|
||||
#define MS_OP_RASSERT_P 17 /* rassert_p <iter>, <reg> */
|
||||
#define MS_OP_RFETCH_P 18 /* rfetch_p <iter>, <reg>, <mask> */
|
||||
#define MS_OP_TRIG 19 /* trigger <reg>, <len>, <array> */
|
||||
|
||||
/* common masks */
|
||||
#define MS_CLEAR_ALL 0x0
|
||||
#define MS_ASSERT_NONE 0x0
|
||||
#define MS_ASSERT_ALL 0xff
|
||||
#define MS_FETCH_ALL 0xff
|
||||
|
||||
/* undefined parameter value */
|
||||
#define MS_UNKNOWN 0
|
||||
|
||||
/* these are register numbers according to our PC-like parallel port model */
|
||||
#define MS_REG_DTR 0x0
|
||||
#define MS_REG_STR 0x1
|
||||
#define MS_REG_CTR 0x2
|
||||
#define MS_REG_EPP 0x4
|
||||
|
||||
/*
|
||||
* Microsequence macro abstraction level
|
||||
*/
|
||||
|
||||
/* register operations */
|
||||
#define MS_RSET(reg,assert,clear) { MS_OP_RSET, { reg, assert, clear} }
|
||||
#define MS_RASSERT(reg,byte) { MS_OP_RASSERT, { reg, byte } }
|
||||
#define MS_RCLR(reg,clear) { MS_OP_RSET, { reg, MS_ASSERT_NONE, clear } }
|
||||
|
||||
#define MS_RFETCH(reg,mask,ptr) { MS_OP_RFETCH, { reg, mask, ptr } }
|
||||
|
||||
/* trigger the port with array[char, delay,...] */
|
||||
#define MS_TRIG(reg,len,array) { MS_OP_TRIG, { reg, len, array } }
|
||||
|
||||
/* assert/fetch from/to ptr */
|
||||
#define MS_RASSERT_P(n,reg) { MS_OP_RASSERT_P, { n, reg } }
|
||||
#define MS_RFETCH_P(n,reg,mask) { MS_OP_RFETCH_P, { n, reg, mask } }
|
||||
|
||||
/* ptr manipulation */
|
||||
#define MS_PTR(ptr) { MS_OP_PTR, { ptr } }
|
||||
|
||||
#define MS_DASS(byte) MS_RASSERT(MS_REG_DTR,byte)
|
||||
#define MS_SASS(byte) MS_RASSERT(MS_REG_STR,byte)
|
||||
#define MS_CASS(byte) MS_RASSERT(MS_REG_CTR,byte)
|
||||
|
||||
#define MS_SET(offset) { MS_OP_SET, { offset } }
|
||||
#define MS_BRSET(mask,offset) { MS_OP_BRSET, { mask, offset } }
|
||||
#define MS_DBRA(offset) { MS_OP_DBRA, { offset } }
|
||||
|
||||
/* C function or submicrosequence call */
|
||||
#define MS_C_CALL(function,parameter) \
|
||||
{ MS_OP_C_CALL, { function, parameter } }
|
||||
#define MS_CALL(microseq) { MS_OP_CALL, { microseq } }
|
||||
|
||||
/* mode dependent read/write operations
|
||||
* ppb_MS_xxx_init() call required otherwise default is
|
||||
* IEEE1284 operating mode */
|
||||
#define MS_PUT(ptr,len) { MS_OP_PUT, { ptr, len } }
|
||||
#define MS_GET(ptr,len) { MS_OP_GET, { ptr, len } }
|
||||
|
||||
/* delay in microseconds */
|
||||
#define MS_DELAY(delay) { MS_OP_DELAY, { delay } }
|
||||
|
||||
/* return from submicrosequence execution or microseqence execution */
|
||||
#define MS_SUBRET(code) { MS_OP_SUBRET, { code } }
|
||||
#define MS_RET(code) { MS_OP_RET, { code } }
|
||||
|
||||
/*
|
||||
* Function abstraction level
|
||||
*/
|
||||
|
||||
#define ppb_MS_GET_init(dev,body) ppb_MS_init(dev, body, MS_OP_GET)
|
||||
|
||||
#define ppb_MS_PUT_init(dev,body) ppb_MS_init(dev, body, MS_OP_PUT)
|
||||
|
||||
extern int ppb_MS_init(
|
||||
struct ppb_device *, /* ppbus device */
|
||||
struct ppb_microseq *, /* loop msq to assign */
|
||||
int opcode /* MS_OP_GET, MS_OP_PUT */
|
||||
);
|
||||
|
||||
extern int ppb_MS_init_msq(
|
||||
struct ppb_microseq *,
|
||||
int, /* number of parameters */
|
||||
... /* descriptor, value, ... */
|
||||
);
|
||||
|
||||
extern int ppb_MS_exec(
|
||||
struct ppb_device *, /* ppbus device */
|
||||
int, /* microseq opcode */
|
||||
union ppb_insarg, /* param1 */
|
||||
union ppb_insarg, /* param2 */
|
||||
union ppb_insarg, /* param3 */
|
||||
int * /* returned value */
|
||||
);
|
||||
|
||||
extern int ppb_MS_loop(
|
||||
struct ppb_device *, /* ppbus device */
|
||||
struct ppb_microseq *, /* prologue msq of loop */
|
||||
struct ppb_microseq *, /* body msq of loop */
|
||||
struct ppb_microseq *, /* epilogue msq of loop */
|
||||
int, /* number of iter */
|
||||
int * /* returned value */
|
||||
);
|
||||
|
||||
extern int ppb_MS_microseq(
|
||||
struct ppb_device *, /* ppbus device */
|
||||
struct ppb_microseq *, /* msq to execute */
|
||||
int * /* returned value */
|
||||
);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Nicolas Souchu
|
||||
* Copyright (c) 1997, 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_1284.h>
|
||||
|
||||
static LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */
|
||||
LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */
|
||||
|
||||
/*
|
||||
* Add a null driver so that the linker set always exists.
|
||||
|
|
@ -53,7 +53,6 @@ DATA_SET(ppbdriver_set, nulldriver);
|
|||
* ppb_alloc_bus()
|
||||
*
|
||||
* Allocate area to store the ppbus description.
|
||||
* This function is called by ppcattach().
|
||||
*/
|
||||
struct ppb_data *
|
||||
ppb_alloc_bus(void)
|
||||
|
|
@ -137,8 +136,8 @@ ppb_pnp_detect(struct ppb_data *ppb)
|
|||
{
|
||||
char *token, *q, *class = 0;
|
||||
int i, len, error;
|
||||
int class_id = -1;
|
||||
char str[PPB_PnP_STRING_SIZE+1];
|
||||
|
||||
struct ppb_device pnpdev; /* temporary device to perform I/O */
|
||||
|
||||
/* initialize the pnpdev structure for future use */
|
||||
|
|
@ -146,44 +145,48 @@ ppb_pnp_detect(struct ppb_data *ppb)
|
|||
|
||||
pnpdev.ppb = ppb;
|
||||
|
||||
#ifdef PnP_DEBUG
|
||||
printf("ppb: <PnP> probing PnP devices on ppbus%d...\n",
|
||||
ppb->ppb_link->adapter_unit);
|
||||
#endif
|
||||
if (bootverbose)
|
||||
printf("ppb: <PnP> probing devices on ppbus %d...\n",
|
||||
ppb->ppb_link->adapter_unit);
|
||||
|
||||
if (ppb_request_bus(&pnpdev, PPB_DONTWAIT)) {
|
||||
if (bootverbose)
|
||||
printf("ppb: <PnP> cannot allocate ppbus!\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ppb_wctr(&pnpdev, nINIT | SELECTIN);
|
||||
|
||||
/* select NIBBLE_1284_REQUEST_ID mode */
|
||||
if ((error = nibble_1284_mode(&pnpdev, NIBBLE_1284_REQUEST_ID))) {
|
||||
#ifdef PnP_DEBUG
|
||||
printf("ppb: <PnP> nibble_1284_mode()=%d\n", error);
|
||||
#endif
|
||||
return (-1);
|
||||
if (bootverbose)
|
||||
printf("ppb: <PnP> nibble_1284_mode()=%d\n", error);
|
||||
goto end_detect;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
for (q = str; !(ppb_rstr(&pnpdev) & ERROR); q++) {
|
||||
if ((error = nibble_1284_inbyte(&pnpdev, q))) {
|
||||
#ifdef PnP_DEBUG
|
||||
printf("ppb: <PnP> nibble_1284_inbyte()=%d\n", error);
|
||||
#endif
|
||||
return (-1);
|
||||
if (bootverbose)
|
||||
printf("ppb: <PnP> nibble_1284_inbyte()=%d\n",
|
||||
error);
|
||||
goto end_detect;
|
||||
}
|
||||
if (len++ >= PPB_PnP_STRING_SIZE) {
|
||||
printf("ppb: <PnP> not space left!\n");
|
||||
return (-1);
|
||||
goto end_detect;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
nibble_1284_sync(&pnpdev);
|
||||
|
||||
#ifdef PnP_DEBUG
|
||||
printf("ppb: <PnP> %d characters: ", len);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("0x%x ", str[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
if (bootverbose) {
|
||||
printf("ppb: <PnP> %d characters: ", len);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("0x%x ", str[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* replace ';' characters by '\0' */
|
||||
for (i = 0; i < len; i++)
|
||||
|
|
@ -226,12 +229,16 @@ ppb_pnp_detect(struct ppb_data *ppb)
|
|||
/* identify class ident */
|
||||
for (i = 0; pnp_tokens[i] != NULL; i++) {
|
||||
if (search_token(class, len, pnp_tokens[i]) != NULL) {
|
||||
return (i);
|
||||
break;
|
||||
class_id = i;
|
||||
goto end_detect;
|
||||
}
|
||||
}
|
||||
|
||||
return (PPB_PnP_UNKNOWN);
|
||||
class_id = PPB_PnP_UNKNOWN;
|
||||
|
||||
end_detect:
|
||||
ppb_release_bus(&pnpdev);
|
||||
return (class_id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -304,6 +311,24 @@ ppb_lookup_bus(int base_port)
|
|||
return (ppb);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_lookup_link()
|
||||
*
|
||||
* Get ppb_data structure pointer according to the unit value
|
||||
* of the corresponding link structure
|
||||
*/
|
||||
struct ppb_data *
|
||||
ppb_lookup_link(int unit)
|
||||
{
|
||||
struct ppb_data *ppb;
|
||||
|
||||
for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
|
||||
if (ppb->ppb_link->adapter_unit == unit)
|
||||
break;
|
||||
|
||||
return (ppb);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_attach_device()
|
||||
*
|
||||
|
|
@ -370,6 +395,15 @@ ppb_request_bus(struct ppb_device *dev, int how)
|
|||
} else {
|
||||
ppb->ppb_owner = dev;
|
||||
|
||||
/* restore the context of the device
|
||||
* The first time, ctx.valid is certainly false
|
||||
* then do not change anything. This is usefull for
|
||||
* drivers that do not set there operating mode
|
||||
* during attachement
|
||||
*/
|
||||
if (dev->ctx.valid)
|
||||
ppb_set_mode(dev, dev->ctx.mode);
|
||||
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -398,6 +432,12 @@ ppb_release_bus(struct ppb_device *dev)
|
|||
ppb->ppb_owner = 0;
|
||||
splx(s);
|
||||
|
||||
/* save the context of the device */
|
||||
dev->ctx.mode = ppb_get_mode(dev);
|
||||
|
||||
/* ok, now the context of the device is valid */
|
||||
dev->ctx.valid = 1;
|
||||
|
||||
/* wakeup waiting processes */
|
||||
wakeup(ppb);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Nicolas Souchu
|
||||
* Copyright (c) 1997, 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppbconf.h,v 1.5 1997/09/01 18:39:37 bde Exp $
|
||||
* $Id: ppbconf.h,v 1.6 1998/06/07 19:44:21 phk Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPBCONF_H
|
||||
|
|
@ -37,21 +37,23 @@
|
|||
#define PPBPRI PZERO+8
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset modes.
|
||||
* Parallel Port Chipset mode masks.
|
||||
* NIBBLE mode is supposed to be available under each other modes.
|
||||
*/
|
||||
#define PPB_AUTODETECT 0x0 /* autodetect */
|
||||
#define PPB_NIBBLE 0x1 /* standard 4 bit mode */
|
||||
#define PPB_COMPATIBLE 0x0 /* Centronics compatible mode */
|
||||
|
||||
#define PPB_NIBBLE 0x1 /* reverse 4 bit mode */
|
||||
#define PPB_PS2 0x2 /* PS/2 byte mode */
|
||||
#define PPB_EPP 0x3 /* EPP mode, 32 bit */
|
||||
#define PPB_ECP_EPP 0x4 /* ECP in EPP mode */
|
||||
#define PPB_ECP_PS2 0x5 /* ECP in PS/2 mode */
|
||||
#define PPB_ECP 0x6 /* ECP mode */
|
||||
#define PPB_UNKNOWN 0x7 /* the last one */
|
||||
#define PPB_EPP 0x4 /* EPP mode, 32 bit */
|
||||
#define PPB_ECP 0x8 /* ECP mode */
|
||||
|
||||
#define PPB_IS_EPP(mode) (mode == PPB_EPP || mode == PPB_ECP_EPP)
|
||||
#define PPB_SPP PPB_NIBBLE|PPB_PS2
|
||||
|
||||
#define PPB_IS_EPP(mode) (mode & PPB_EPP)
|
||||
#define PPB_IN_EPP_MODE(dev) (PPB_IS_EPP (ppb_get_mode (dev)))
|
||||
|
||||
#define n(flags) (~(flags) & (flags))
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset control bits.
|
||||
*/
|
||||
|
|
@ -62,6 +64,12 @@
|
|||
#define IRQENABLE 0x10
|
||||
#define PCD 0x20
|
||||
|
||||
#define nSTROBE n(STROBE)
|
||||
#define nAUTOFEED n(AUTOFEED)
|
||||
#define INIT n(nINIT)
|
||||
#define nSELECTIN n(SELECTIN)
|
||||
#define nPCD n(PCD)
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset status bits.
|
||||
*/
|
||||
|
|
@ -87,21 +95,74 @@ struct ppb_status {
|
|||
};
|
||||
|
||||
/*
|
||||
* How tsleep () is called in ppb_request_bus ().
|
||||
* How tsleep() is called in ppb_request_bus().
|
||||
*/
|
||||
#define PPB_DONTWAIT 0
|
||||
#define PPB_NOINTR 0
|
||||
#define PPB_WAIT 0x1
|
||||
#define PPB_INTR 0x2
|
||||
|
||||
struct ppb_data; /* see below */
|
||||
/*
|
||||
* Microsequence stuff.
|
||||
*/
|
||||
#define PPB_MS_MAXLEN 64 /* XXX according to MS_INS_MASK */
|
||||
#define PPB_MS_MAXARGS 3 /* according to MS_ARG_MASK */
|
||||
|
||||
/* maximum number of mode dependent
|
||||
* submicrosequences for in/out operations
|
||||
*/
|
||||
#define PPB_MAX_XFER 6
|
||||
|
||||
union ppb_insarg {
|
||||
int i;
|
||||
char c;
|
||||
void *p;
|
||||
int (* f)(void *, char *);
|
||||
};
|
||||
|
||||
struct ppb_microseq {
|
||||
int opcode; /* microins. opcode */
|
||||
union ppb_insarg arg[PPB_MS_MAXARGS]; /* arguments */
|
||||
};
|
||||
|
||||
/* microseqences used for GET/PUT operations */
|
||||
struct ppb_xfer {
|
||||
struct ppb_microseq *loop; /* the loop microsequence */
|
||||
};
|
||||
|
||||
/*
|
||||
* Parallel Port Bus Device structure.
|
||||
*/
|
||||
struct ppb_data; /* see below */
|
||||
|
||||
struct ppb_context {
|
||||
int valid; /* 1 if the struct is valid */
|
||||
int mode; /* XXX chipset operating mode */
|
||||
|
||||
struct microseq *curpc; /* pc in curmsq */
|
||||
struct microseq *curmsq; /* currently executed microseqence */
|
||||
};
|
||||
|
||||
|
||||
struct ppb_device {
|
||||
|
||||
int id_unit; /* unit of the device */
|
||||
char *name; /* name of the device */
|
||||
|
||||
ushort mode; /* current mode of the device */
|
||||
ushort avm; /* available modes of the device */
|
||||
|
||||
struct ppb_context ctx; /* context of the device */
|
||||
|
||||
/* mode dependent get msq. If NULL,
|
||||
* IEEE1284 code is used */
|
||||
struct ppb_xfer
|
||||
get_xfer[PPB_MAX_XFER];
|
||||
|
||||
/* mode dependent put msq. If NULL,
|
||||
* IEEE1284 code is used */
|
||||
struct ppb_xfer
|
||||
put_xfer[PPB_MAX_XFER];
|
||||
|
||||
void (*intr)(int); /* interrupt handler */
|
||||
|
||||
|
|
@ -119,6 +180,10 @@ struct ppb_adapter {
|
|||
void (*reset_epp_timeout)(int);
|
||||
void (*ecp_sync)(int);
|
||||
|
||||
int (*exec_microseq)(int, struct ppb_microseq *, int *);
|
||||
|
||||
int (*setmode)(int, int);
|
||||
|
||||
void (*outsb_epp)(int, char *, int);
|
||||
void (*outsw_epp)(int, char *, int);
|
||||
void (*outsl_epp)(int, char *, int);
|
||||
|
|
@ -147,10 +212,8 @@ struct ppb_adapter {
|
|||
struct ppb_link {
|
||||
|
||||
int adapter_unit; /* unit of the adapter */
|
||||
|
||||
int base; /* base address of the port */
|
||||
int id_irq; /* != 0 if irq enabled */
|
||||
int mode; /* NIBBLE, PS2, EPP, ECP */
|
||||
|
||||
#define EPP_1_9 0x0 /* default */
|
||||
#define EPP_1_7 0x1
|
||||
|
|
@ -164,7 +227,7 @@ struct ppb_link {
|
|||
/*
|
||||
* Maximum size of the PnP info string
|
||||
*/
|
||||
#define PPB_PnP_STRING_SIZE 160 /* XXX */
|
||||
#define PPB_PnP_STRING_SIZE 128 /* XXX */
|
||||
|
||||
/*
|
||||
* Parallel Port Bus structure.
|
||||
|
|
@ -184,6 +247,11 @@ struct ppb_data {
|
|||
#define PPB_PnP_UNKNOWN 10
|
||||
int class_id; /* not a PnP device if class_id < 0 */
|
||||
|
||||
ushort mode; /* IEEE 1284-1994 mode
|
||||
* NIBBLE, PS2, EPP or ECP */
|
||||
ushort avm; /* IEEE 1284-1994 available
|
||||
* modes */
|
||||
|
||||
struct ppb_link *ppb_link; /* link to the adapter */
|
||||
struct ppb_device *ppb_owner; /* device which owns the bus */
|
||||
LIST_HEAD(, ppb_device) ppb_devs; /* list of devices on the bus */
|
||||
|
|
@ -205,6 +273,7 @@ extern struct linker_set ppbdriver_set;
|
|||
extern struct ppb_data *ppb_alloc_bus(void);
|
||||
extern struct ppb_data *ppb_next_bus(struct ppb_data *);
|
||||
extern struct ppb_data *ppb_lookup_bus(int);
|
||||
extern struct ppb_data *ppb_lookup_link(int);
|
||||
|
||||
extern int ppb_attach_device(struct ppb_device *);
|
||||
extern void ppb_remove_device(struct ppb_device *);
|
||||
|
|
@ -220,56 +289,61 @@ extern int ppb_poll_device(struct ppb_device *, int, char, char, int);
|
|||
extern int ppb_reset_epp_timeout(struct ppb_device *);
|
||||
extern int ppb_ecp_sync(struct ppb_device *);
|
||||
extern int ppb_get_status(struct ppb_device *, struct ppb_status *);
|
||||
extern int ppb_get_mode(struct ppb_device *);
|
||||
extern int ppb_get_epp_protocol(struct ppb_device *);
|
||||
extern int ppb_get_irq(struct ppb_device *);
|
||||
|
||||
extern int ppb_set_mode(struct ppb_device *, int);
|
||||
|
||||
/*
|
||||
* These are defined as macros for speedup.
|
||||
*/
|
||||
#define ppb_outsb_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->outsb_epp) \
|
||||
#define ppb_get_base_addr(dev) ((dev)->ppb->ppb_link->base)
|
||||
#define ppb_get_epp_protocol(dev) ((dev)->ppb->ppb_link->epp_protocol)
|
||||
#define ppb_get_irq(dev) ((dev)->ppb->ppb_link->id_irq)
|
||||
|
||||
#define ppb_get_mode(dev) ((dev)->mode)
|
||||
|
||||
#define ppb_outsb_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->outsb_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
|
||||
#define ppb_outsw_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->outsw_epp) \
|
||||
#define ppb_outsw_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->outsw_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
|
||||
#define ppb_outsl_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->outsl_epp) \
|
||||
#define ppb_outsl_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->outsl_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
|
||||
#define ppb_insb_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->insb_epp) \
|
||||
#define ppb_insb_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->insb_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
|
||||
#define ppb_insw_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->insw_epp) \
|
||||
#define ppb_insw_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->insw_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
|
||||
#define ppb_insl_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->insl_epp) \
|
||||
#define ppb_insl_epp(dev,buf,cnt) \
|
||||
(*(dev)->ppb->ppb_link->adapter->insl_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
|
||||
|
||||
#define ppb_rdtr(dev) (*(dev)->ppb->ppb_link->adapter->r_dtr) \
|
||||
#define ppb_repp(dev) (*(dev)->ppb->ppb_link->adapter->r_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_rstr(dev) (*(dev)->ppb->ppb_link->adapter->r_str) \
|
||||
#define ppb_recr(dev) (*(dev)->ppb->ppb_link->adapter->r_ecr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_rctr(dev) (*(dev)->ppb->ppb_link->adapter->r_ctr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_repp(dev) (*(dev)->ppb->ppb_link->adapter->r_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_recr(dev) (*(dev)->ppb->ppb_link->adapter->r_ecr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_rfifo(dev) (*(dev)->ppb->ppb_link->adapter->r_fifo) \
|
||||
#define ppb_rfifo(dev) (*(dev)->ppb->ppb_link->adapter->r_fifo) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_wepp(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
#define ppb_wecr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_ecr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
#define ppb_wfifo(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_fifo) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
|
||||
#define ppb_wdtr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_dtr) \
|
||||
#define ppb_rdtr(dev) (*(dev)->ppb->ppb_link->adapter->r_dtr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_rstr(dev) (*(dev)->ppb->ppb_link->adapter->r_str) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_rctr(dev) (*(dev)->ppb->ppb_link->adapter->r_ctr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit)
|
||||
#define ppb_wdtr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_dtr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
#define ppb_wstr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_str) \
|
||||
#define ppb_wstr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_str) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
#define ppb_wctr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_ctr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
#define ppb_wepp(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_epp) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
#define ppb_wecr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_ecr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
#define ppb_wfifo(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_fifo) \
|
||||
#define ppb_wctr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_ctr) \
|
||||
((dev)->ppb->ppb_link->adapter_unit, byte)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* $Id: pps.c,v 1.8 1998/06/13 09:30:10 phk Exp $
|
||||
* $Id: pps.c,v 1.9 1998/06/21 18:02:32 bde Exp $
|
||||
*
|
||||
* This driver implements a draft-mogul-pps-api-02.txt PPS source.
|
||||
*
|
||||
|
|
@ -93,6 +93,7 @@ ppsprobe(struct ppb_data *ppb)
|
|||
|
||||
sc->pps_dev.id_unit = sc->pps_unit;
|
||||
sc->pps_dev.ppb = ppb;
|
||||
sc->pps_dev.name = ppsdriver.name;
|
||||
sc->pps_dev.intr = ppsintr;
|
||||
|
||||
return (&sc->pps_dev);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Nicolas Souchu
|
||||
* Copyright (c) 1997, 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -44,39 +44,42 @@
|
|||
#endif /*KERNEL */
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/vpo.h>
|
||||
#include <dev/ppbus/vpoio.h>
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* HERE ARE THINGS YOU MAY HAVE/WANT TO CHANGE
|
||||
*/
|
||||
#define VP0_BUFFER_SIZE 0x12000
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* We may add a timeout queue to avoid active polling on nACK.
|
||||
*/
|
||||
#define VP0_SELTMO 5000 /* select timeout */
|
||||
#define VP0_FAST_SPINTMO 500000 /* wait status timeout */
|
||||
#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */
|
||||
struct vpo_sense {
|
||||
struct scsi_sense cmd;
|
||||
unsigned int stat;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
/*
|
||||
* DO NOT MODIFY ANYTHING UNDER THIS LINE
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
struct vpo_data {
|
||||
unsigned short vpo_unit;
|
||||
|
||||
int vpo_stat;
|
||||
int vpo_count;
|
||||
int vpo_error;
|
||||
|
||||
struct ppb_status vpo_status;
|
||||
struct vpo_sense vpo_sense;
|
||||
|
||||
unsigned char vpo_buffer[VP0_BUFFER_SIZE];
|
||||
|
||||
struct vpoio_data vpo_io; /* interface to low level functions */
|
||||
|
||||
struct scsi_link sc_link;
|
||||
};
|
||||
|
||||
static __inline int vpoio_do_scsi(struct vpo_data *, int, int, char *, int,
|
||||
char *, int, int *, int *);
|
||||
|
||||
static int32_t vpo_scsi_cmd(struct scsi_xfer *);
|
||||
static void vpominphys(struct buf *);
|
||||
static u_int32_t vpo_adapter_info(int);
|
||||
|
||||
static int vpo_detect(struct vpo_data *vpo);
|
||||
|
||||
static int nvpo = 0;
|
||||
#define MAXVP0 8 /* XXX not much better! */
|
||||
static struct vpo_data *vpodata[MAXVP0];
|
||||
|
||||
#ifdef KERNEL
|
||||
static struct scsi_adapter vpo_switch =
|
||||
{
|
||||
vpo_scsi_cmd,
|
||||
|
|
@ -117,8 +120,6 @@ static struct ppb_driver vpodriver = {
|
|||
DATA_SET(ppbdriver_set, vpodriver);
|
||||
|
||||
|
||||
#endif /* KERNEL */
|
||||
|
||||
static u_int32_t
|
||||
vpo_adapter_info(int unit)
|
||||
{
|
||||
|
|
@ -134,8 +135,8 @@ vpo_adapter_info(int unit)
|
|||
static struct ppb_device *
|
||||
vpoprobe(struct ppb_data *ppb)
|
||||
{
|
||||
|
||||
struct vpo_data *vpo;
|
||||
struct ppb_device *dev;
|
||||
|
||||
if (nvpo >= MAXVP0) {
|
||||
printf("vpo: Too many devices (max %d)\n", MAXVP0);
|
||||
|
|
@ -155,20 +156,18 @@ vpoprobe(struct ppb_data *ppb)
|
|||
/* vpo dependent initialisation */
|
||||
vpo->vpo_unit = nvpo;
|
||||
|
||||
/* ppbus dependent initialisation */
|
||||
vpo->vpo_dev.id_unit = vpo->vpo_unit;
|
||||
vpo->vpo_dev.ppb = ppb;
|
||||
/* ok, go to next device on next probe */
|
||||
nvpo ++;
|
||||
|
||||
/* now, try to initialise the drive */
|
||||
if (vpo_detect(vpo)) {
|
||||
/* low level probe */
|
||||
vpoio_set_unit(&vpo->vpo_io, vpo->vpo_unit);
|
||||
|
||||
if (!(dev = vpoio_probe(ppb, &vpo->vpo_io))) {
|
||||
free(vpo, M_DEVBUF);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* ok, go to next device on next probe */
|
||||
nvpo ++;
|
||||
|
||||
return (&vpo->vpo_dev);
|
||||
return (dev);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -183,18 +182,16 @@ vpoattach(struct ppb_device *dev)
|
|||
struct scsibus_data *scbus;
|
||||
struct vpo_data *vpo = vpodata[dev->id_unit];
|
||||
|
||||
/* low level attachment */
|
||||
if (!vpoio_attach(&vpo->vpo_io))
|
||||
return (0);
|
||||
|
||||
vpo->sc_link.adapter_unit = vpo->vpo_unit;
|
||||
vpo->sc_link.adapter_targ = VP0_INITIATOR;
|
||||
vpo->sc_link.adapter = &vpo_switch;
|
||||
vpo->sc_link.device = &vpo_dev;
|
||||
vpo->sc_link.opennings = VP0_OPENNINGS;
|
||||
|
||||
/*
|
||||
* Report ourselves
|
||||
*/
|
||||
printf("vpo%d: <Adaptec aic7110 scsi> on ppbus %d\n",
|
||||
dev->id_unit, dev->ppb->ppb_link->adapter_unit);
|
||||
|
||||
/*
|
||||
* Prepare the scsibus_data area for the upperlevel
|
||||
* scsi code.
|
||||
|
|
@ -204,6 +201,9 @@ vpoattach(struct ppb_device *dev)
|
|||
return (0);
|
||||
scbus->adapter_link = &vpo->sc_link;
|
||||
|
||||
/* all went ok */
|
||||
printf("vpo%d: <Iomega PPA-3/VPI0 SCSI controller>\n", dev->id_unit);
|
||||
|
||||
scsi_attachdevs(scbus);
|
||||
|
||||
return (1);
|
||||
|
|
@ -219,58 +219,11 @@ vpominphys(struct buf *bp)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef VP0_WARNING
|
||||
static __inline void
|
||||
vpo_warning(struct vpo_data *vpo, struct scsi_xfer *xs, int timeout)
|
||||
{
|
||||
|
||||
switch (timeout) {
|
||||
case 0:
|
||||
case VP0_ESELECT_TIMEOUT:
|
||||
/* log(LOG_WARNING,
|
||||
"vpo%d: select timeout\n", vpo->vpo_unit); */
|
||||
break;
|
||||
case VP0_EDISCONNECT:
|
||||
log(LOG_WARNING,
|
||||
"vpo%d: can't get printer state\n", vpo->vpo_unit);
|
||||
break;
|
||||
case VP0_ECONNECT:
|
||||
log(LOG_WARNING,
|
||||
"vpo%d: can't get disk state\n", vpo->vpo_unit);
|
||||
break;
|
||||
case VP0_ECMD_TIMEOUT:
|
||||
log(LOG_WARNING,
|
||||
"vpo%d: command timeout\n", vpo->vpo_unit);
|
||||
break;
|
||||
case VP0_EPPDATA_TIMEOUT:
|
||||
log(LOG_WARNING,
|
||||
"vpo%d: EPP data timeout\n", vpo->vpo_unit);
|
||||
break;
|
||||
case VP0_ESTATUS_TIMEOUT:
|
||||
log(LOG_WARNING,
|
||||
"vpo%d: status timeout\n", vpo->vpo_unit);
|
||||
break;
|
||||
case VP0_EDATA_OVERFLOW:
|
||||
log(LOG_WARNING,
|
||||
"vpo%d: data overflow\n", vpo->vpo_unit);
|
||||
break;
|
||||
case VP0_EINTR:
|
||||
log(LOG_WARNING,
|
||||
"vpo%d: ppb request interrupted\n", vpo->vpo_unit);
|
||||
break;
|
||||
default:
|
||||
log(LOG_WARNING,
|
||||
"vpo%d: timeout = %d\n", vpo->vpo_unit, timeout);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* VP0_WARNING */
|
||||
|
||||
/*
|
||||
* vpointr()
|
||||
* vpo_intr()
|
||||
*/
|
||||
static __inline void
|
||||
vpointr(struct vpo_data *vpo, struct scsi_xfer *xs)
|
||||
static void
|
||||
vpo_intr(struct vpo_data *vpo, struct scsi_xfer *xs)
|
||||
{
|
||||
|
||||
int errno; /* error in errno.h */
|
||||
|
|
@ -278,9 +231,10 @@ vpointr(struct vpo_data *vpo, struct scsi_xfer *xs)
|
|||
if (xs->datalen && !(xs->flags & SCSI_DATA_IN))
|
||||
bcopy(xs->data, vpo->vpo_buffer, xs->datalen);
|
||||
|
||||
errno = vpoio_do_scsi(vpo, VP0_INITIATOR,
|
||||
errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
|
||||
xs->sc_link->target, (char *)xs->cmd, xs->cmdlen,
|
||||
vpo->vpo_buffer, xs->datalen, &vpo->vpo_stat, &vpo->vpo_count);
|
||||
vpo->vpo_buffer, xs->datalen, &vpo->vpo_stat, &vpo->vpo_count,
|
||||
&vpo->vpo_error);
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
|
||||
|
|
@ -298,9 +252,6 @@ vpointr(struct vpo_data *vpo, struct scsi_xfer *xs)
|
|||
|
||||
/* if a timeout occured, no sense */
|
||||
if (vpo->vpo_error) {
|
||||
#ifdef VP0_WARNING
|
||||
vpo_warning(vpo, xs, vpo->vpo_error);
|
||||
#endif
|
||||
xs->error = XS_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -318,11 +269,12 @@ vpointr(struct vpo_data *vpo, struct scsi_xfer *xs)
|
|||
vpo->vpo_sense.cmd.length = sizeof(xs->sense);
|
||||
vpo->vpo_sense.cmd.control = 0;
|
||||
|
||||
errno = vpoio_do_scsi(vpo, VP0_INITIATOR,
|
||||
errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
|
||||
xs->sc_link->target, (char *)&vpo->vpo_sense.cmd,
|
||||
sizeof(vpo->vpo_sense.cmd),
|
||||
(char *)&xs->sense, sizeof(xs->sense),
|
||||
&vpo->vpo_sense.stat, &vpo->vpo_sense.count);
|
||||
&vpo->vpo_sense.stat, &vpo->vpo_sense.count,
|
||||
&vpo->vpo_error);
|
||||
|
||||
if (errno)
|
||||
/* connection to ppbus interrupted */
|
||||
|
|
@ -376,490 +328,14 @@ vpo_scsi_cmd(struct scsi_xfer *xs)
|
|||
#endif
|
||||
|
||||
if (xs->flags & SCSI_NOMASK) {
|
||||
vpointr(vpodata[xs->sc_link->adapter_unit], xs);
|
||||
vpo_intr(vpodata[xs->sc_link->adapter_unit], xs);
|
||||
return COMPLETE;
|
||||
}
|
||||
|
||||
s = VP0_SPL();
|
||||
s = splbio();
|
||||
|
||||
vpointr(vpodata[xs->sc_link->adapter_unit], xs);
|
||||
vpo_intr(vpodata[xs->sc_link->adapter_unit], xs);
|
||||
|
||||
splx(s);
|
||||
return SUCCESSFULLY_QUEUED;
|
||||
}
|
||||
|
||||
#define vpoio_d_pulse(vpo,b) { \
|
||||
ppb_wdtr(&(vpo)->vpo_dev, b); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
}
|
||||
|
||||
#define vpoio_c_pulse(vpo,b) { \
|
||||
ppb_wdtr(&(vpo)->vpo_dev, b); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
}
|
||||
|
||||
static int
|
||||
vpoio_disconnect(struct vpo_data *vpo)
|
||||
{
|
||||
|
||||
vpoio_d_pulse(vpo, 0);
|
||||
vpoio_d_pulse(vpo, 0x3c);
|
||||
vpoio_d_pulse(vpo, 0x20);
|
||||
vpoio_d_pulse(vpo, 0xf);
|
||||
|
||||
return (ppb_release_bus(&vpo->vpo_dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* how : PPB_WAIT or PPB_DONTWAIT
|
||||
*/
|
||||
static int
|
||||
vpoio_connect(struct vpo_data *vpo, int how)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = ppb_request_bus(&vpo->vpo_dev, how)))
|
||||
return error;
|
||||
|
||||
vpoio_c_pulse(vpo, 0);
|
||||
vpoio_c_pulse(vpo, 0x3c);
|
||||
vpoio_c_pulse(vpo, 0x20);
|
||||
|
||||
if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) {
|
||||
vpoio_c_pulse(vpo, 0xcf);
|
||||
} else {
|
||||
vpoio_c_pulse(vpo, 0x8f);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_in_disk_mode()
|
||||
*
|
||||
* Check if we are in disk mode
|
||||
*/
|
||||
static int
|
||||
vpoio_in_disk_mode(struct vpo_data *vpo)
|
||||
{
|
||||
|
||||
/* first, set H_AUTO high */
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
|
||||
/* when H_AUTO is set low, H_FLT should be high */
|
||||
ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) == 0)
|
||||
return (0);
|
||||
|
||||
/* when H_AUTO is set high, H_FLT should be low */
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) != 0)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_reset()
|
||||
*
|
||||
* SCSI reset signal, the drive must be in disk mode
|
||||
*/
|
||||
static void
|
||||
vpoio_reset (struct vpo_data *vpo)
|
||||
{
|
||||
|
||||
/*
|
||||
* SCSI reset signal.
|
||||
*/
|
||||
ppb_wdtr(&vpo->vpo_dev, (1 << 7));
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE);
|
||||
DELAY(25);
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vpo_detect()
|
||||
*
|
||||
* Detect and initialise the VP0 adapter.
|
||||
*/
|
||||
static int
|
||||
vpo_detect(struct vpo_data *vpo)
|
||||
{
|
||||
|
||||
vpoio_disconnect(vpo);
|
||||
vpoio_connect(vpo, PPB_DONTWAIT);
|
||||
|
||||
if (!vpoio_in_disk_mode(vpo)) {
|
||||
vpoio_disconnect(vpo);
|
||||
return (VP0_EINITFAILED);
|
||||
}
|
||||
|
||||
/* send SCSI reset signal */
|
||||
vpoio_reset (vpo);
|
||||
|
||||
vpoio_disconnect(vpo);
|
||||
|
||||
if (vpoio_in_disk_mode(vpo))
|
||||
return (VP0_EINITFAILED);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define vpo_wctr(dev,byte,delay) { \
|
||||
int i; int iter = delay / MHZ_16_IO_DURATION; \
|
||||
for (i = 0; i < iter; i++) { \
|
||||
ppb_wctr(dev, byte); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define vpoio_spp_outbyte(vpo,byte) { \
|
||||
ppb_wdtr(&vpo->vpo_dev, byte); \
|
||||
ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
|
||||
vpo_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE, \
|
||||
VP0_SPP_WRITE_PULSE); \
|
||||
}
|
||||
|
||||
#define vpoio_nibble_inbyte(vpo,buffer) { \
|
||||
register char h, l; \
|
||||
vpo_wctr(&vpo->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE, \
|
||||
VP0_NIBBLE_READ_PULSE); \
|
||||
h = ppb_rstr(&vpo->vpo_dev); \
|
||||
ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
|
||||
l = ppb_rstr(&vpo->vpo_dev); \
|
||||
*buffer = ((l >> 4) & 0x0f) + (h & 0xf0); \
|
||||
}
|
||||
|
||||
#define vpoio_ps2_inbyte(vpo,buffer) { \
|
||||
*buffer = ppb_rdtr(&vpo->vpo_dev); \
|
||||
ppb_wctr(&vpo->vpo_dev, PCD | H_nAUTO | H_SELIN | H_INIT | H_nSTROBE); \
|
||||
ppb_wctr(&vpo->vpo_dev, PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE); \
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_outstr()
|
||||
*/
|
||||
static int
|
||||
vpoio_outstr(struct vpo_data *vpo, char *buffer, int size)
|
||||
{
|
||||
|
||||
register int k;
|
||||
int error = 0;
|
||||
int r, mode, epp;
|
||||
|
||||
mode = ppb_get_mode(&vpo->vpo_dev);
|
||||
switch (mode) {
|
||||
case PPB_NIBBLE:
|
||||
case PPB_PS2:
|
||||
for (k = 0; k < size; k++) {
|
||||
vpoio_spp_outbyte(vpo, *buffer++);
|
||||
}
|
||||
break;
|
||||
|
||||
case PPB_EPP:
|
||||
case PPB_ECP_EPP:
|
||||
epp = ppb_get_epp_protocol(&vpo->vpo_dev);
|
||||
|
||||
ppb_reset_epp_timeout(&vpo->vpo_dev);
|
||||
ppb_wctr(&vpo->vpo_dev,
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE);
|
||||
|
||||
if (epp == EPP_1_7)
|
||||
for (k = 0; k < size; k++) {
|
||||
ppb_wepp(&vpo->vpo_dev, *buffer++);
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
|
||||
error = VP0_EPPDATA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (((long) buffer | size) & 0x03)
|
||||
ppb_outsb_epp(&vpo->vpo_dev,
|
||||
buffer, size);
|
||||
else
|
||||
ppb_outsl_epp(&vpo->vpo_dev,
|
||||
buffer, size/4);
|
||||
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
|
||||
error = VP0_EPPDATA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ppb_wctr(&vpo->vpo_dev,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
/* ppb_ecp_sync(&vpo->vpo_dev); */
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("vpoio_outstr(): unknown transfer mode (%d)!\n",
|
||||
mode);
|
||||
return (1); /* XXX */
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_instr()
|
||||
*/
|
||||
static int
|
||||
vpoio_instr(struct vpo_data *vpo, char *buffer, int size)
|
||||
{
|
||||
|
||||
register int k;
|
||||
int error = 0;
|
||||
int r, mode, epp;
|
||||
|
||||
mode = ppb_get_mode(&vpo->vpo_dev);
|
||||
switch (mode) {
|
||||
case PPB_NIBBLE:
|
||||
for (k = 0; k < size; k++) {
|
||||
vpoio_nibble_inbyte(vpo, buffer++);
|
||||
}
|
||||
ppb_wctr(&vpo->vpo_dev,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
break;
|
||||
|
||||
case PPB_PS2:
|
||||
ppb_wctr(&vpo->vpo_dev, PCD |
|
||||
H_AUTO | H_SELIN | H_INIT | H_nSTROBE);
|
||||
|
||||
for (k = 0; k < size; k++) {
|
||||
vpoio_ps2_inbyte(vpo, buffer++);
|
||||
}
|
||||
ppb_wctr(&vpo->vpo_dev,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
break;
|
||||
|
||||
case PPB_EPP:
|
||||
case PPB_ECP_EPP:
|
||||
epp = ppb_get_epp_protocol(&vpo->vpo_dev);
|
||||
|
||||
ppb_reset_epp_timeout(&vpo->vpo_dev);
|
||||
ppb_wctr(&vpo->vpo_dev, PCD |
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE);
|
||||
|
||||
if (epp == EPP_1_7)
|
||||
for (k = 0; k < size; k++) {
|
||||
*buffer++ = ppb_repp(&vpo->vpo_dev);
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
|
||||
error = VP0_EPPDATA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (((long) buffer | size) & 0x03)
|
||||
ppb_insb_epp(&vpo->vpo_dev,
|
||||
buffer, size);
|
||||
else
|
||||
ppb_insl_epp(&vpo->vpo_dev,
|
||||
buffer, size/4);
|
||||
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
|
||||
error = VP0_EPPDATA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ppb_wctr(&vpo->vpo_dev, PCD |
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
/* ppb_ecp_sync(&vpo->vpo_dev); */
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("vpoio_instr(): unknown transfer mode (%d)!\n",
|
||||
mode);
|
||||
return (1); /* XXX */
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static __inline char
|
||||
vpoio_select(struct vpo_data *vpo, int initiator, int target)
|
||||
{
|
||||
|
||||
register int k;
|
||||
|
||||
ppb_wdtr(&vpo->vpo_dev, (1 << target));
|
||||
ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
ppb_wdtr(&vpo->vpo_dev, (1 << initiator));
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE);
|
||||
|
||||
k = 0;
|
||||
while (!(ppb_rstr(&vpo->vpo_dev) & 0x40) && (k++ < VP0_SELTMO))
|
||||
barrier();
|
||||
|
||||
if (k >= VP0_SELTMO)
|
||||
return (VP0_ESELECT_TIMEOUT);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_wait()
|
||||
*
|
||||
* H_SELIN must be low.
|
||||
*/
|
||||
static __inline char
|
||||
vpoio_wait(struct vpo_data *vpo, int tmo)
|
||||
{
|
||||
|
||||
register int k;
|
||||
register char r;
|
||||
|
||||
#if 0 /* broken */
|
||||
if (ppb_poll_device(&vpo->vpo_dev, 150, nBUSY, nBUSY, PPB_INTR))
|
||||
return (0);
|
||||
|
||||
return (ppb_rstr(&vpo->vpo_dev) & 0xf0);
|
||||
#endif
|
||||
|
||||
k = 0;
|
||||
while (!((r = ppb_rstr(&vpo->vpo_dev)) & nBUSY) && (k++ < tmo))
|
||||
barrier();
|
||||
|
||||
/*
|
||||
* Return some status information.
|
||||
* Semantics : 0xc0 = ZIP wants more data
|
||||
* 0xd0 = ZIP wants to send more data
|
||||
* 0xe0 = ZIP wants command
|
||||
* 0xf0 = end of transfer, ZIP is sending status
|
||||
*/
|
||||
if (k < tmo)
|
||||
return (r & 0xf0);
|
||||
|
||||
return (0); /* command timed out */
|
||||
}
|
||||
|
||||
static __inline int
|
||||
vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command,
|
||||
int clen, char *buffer, int blen, int *result, int *count)
|
||||
{
|
||||
|
||||
register char r;
|
||||
char l, h = 0;
|
||||
int rw, len, error = 0;
|
||||
register int k;
|
||||
|
||||
/*
|
||||
* enter disk state, allocate the ppbus
|
||||
*
|
||||
* XXX
|
||||
* Should we allow this call to be interruptible?
|
||||
* The only way to report the interruption is to return
|
||||
* EIO do upper SCSI code :^(
|
||||
*/
|
||||
if ((error = vpoio_connect(vpo, PPB_WAIT|PPB_INTR)))
|
||||
return (error);
|
||||
|
||||
if (!vpoio_in_disk_mode(vpo)) {
|
||||
vpo->vpo_error = VP0_ECONNECT; goto error;
|
||||
}
|
||||
|
||||
if ((vpo->vpo_error = vpoio_select(vpo,host,target)))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Send the command ...
|
||||
*
|
||||
* set H_SELIN low for vpoio_wait().
|
||||
*/
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("vpo%d: drive selected, now sending the command...\n",
|
||||
vpo->vpo_unit);
|
||||
#endif
|
||||
|
||||
for (k = 0; k < clen; k++) {
|
||||
if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) {
|
||||
vpo->vpo_error = VP0_ECMD_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
if (vpoio_outstr(vpo, &command[k], 1)) {
|
||||
vpo->vpo_error = VP0_EPPDATA_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("vpo%d: command sent, now completing the request...\n",
|
||||
vpo->vpo_unit);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Completion ...
|
||||
*/
|
||||
rw = ((command[0] == READ_COMMAND) || (command[0] == READ_BIG) ||
|
||||
(command[0] == WRITE_COMMAND) || (command[0] == WRITE_BIG));
|
||||
|
||||
*count = 0;
|
||||
for (;;) {
|
||||
|
||||
if (!(r = vpoio_wait(vpo, VP0_LOW_SPINTMO))) {
|
||||
vpo->vpo_error = VP0_ESTATUS_TIMEOUT; goto error;
|
||||
}
|
||||
|
||||
/* stop when the ZIP wants to send status */
|
||||
if (r == (char)0xf0)
|
||||
break;
|
||||
|
||||
if (*count >= blen) {
|
||||
vpo->vpo_error = VP0_EDATA_OVERFLOW;
|
||||
goto error;
|
||||
}
|
||||
len = (rw && ((blen - *count) >= VP0_SECTOR_SIZE)) ?
|
||||
VP0_SECTOR_SIZE : 1;
|
||||
|
||||
/* ZIP wants to send data? */
|
||||
if (r == (char)0xc0)
|
||||
error = vpoio_outstr(vpo, &buffer[*count], len);
|
||||
else
|
||||
error = vpoio_instr(vpo, &buffer[*count], len);
|
||||
|
||||
if (error) {
|
||||
vpo->vpo_error = error;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*count += len;
|
||||
}
|
||||
|
||||
if (vpoio_instr(vpo, &l, 1)) {
|
||||
vpo->vpo_error = VP0_EOTHER; goto error;
|
||||
}
|
||||
|
||||
/* check if the ZIP wants to send more status */
|
||||
if (vpoio_wait(vpo, VP0_FAST_SPINTMO) == (char)0xf0)
|
||||
if (vpoio_instr(vpo, &h, 1)) {
|
||||
vpo->vpo_error = VP0_EOTHER+2; goto error;
|
||||
}
|
||||
|
||||
*result = ((int) h << 8) | ((int) l & 0xff);
|
||||
|
||||
error:
|
||||
/* return to printer state, release the ppbus */
|
||||
vpoio_disconnect(vpo);
|
||||
return (0);
|
||||
}
|
||||
|
|
|
|||
771
sys/dev/ppbus/vpoio.c
Normal file
771
sys/dev/ppbus/vpoio.c
Normal file
|
|
@ -0,0 +1,771 @@
|
|||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: vpoio.c,v 1.1.2.4 1998/06/16 23:35:52 son Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/buf.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#endif /* KERNEL */
|
||||
|
||||
#ifdef KERNEL
|
||||
#include <sys/kernel.h>
|
||||
#endif /*KERNEL */
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
#include <dev/ppbus/vpoio.h>
|
||||
|
||||
/*
|
||||
* The driver pools the drive. We may add a timeout queue to avoid
|
||||
* active polling on nACK. I've tried this but it leads to unreliable
|
||||
* transfers
|
||||
*/
|
||||
#define VP0_SELTMO 5000 /* select timeout */
|
||||
#define VP0_FAST_SPINTMO 500000 /* wait status timeout */
|
||||
#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */
|
||||
|
||||
/*
|
||||
* Actually, VP0 timings are more accurate (about few 16MHZ cycles),
|
||||
* but succeeding in respecting such timings leads to architecture
|
||||
* dependent considerations.
|
||||
*/
|
||||
#define VP0_PULSE 1
|
||||
|
||||
#define VP0_SECTOR_SIZE 512
|
||||
#define VP0_BUFFER_SIZE 0x12000
|
||||
|
||||
#define n(flags) (~(flags) & (flags))
|
||||
|
||||
/*
|
||||
* VP0 connections.
|
||||
*/
|
||||
#define H_AUTO n(AUTOFEED)
|
||||
#define H_nAUTO AUTOFEED
|
||||
#define H_STROBE n(STROBE)
|
||||
#define H_nSTROBE STROBE
|
||||
#define H_BSY n(nBUSY)
|
||||
#define H_nBSY nBUSY
|
||||
#define H_SEL SELECT
|
||||
#define H_nSEL n(SELECT)
|
||||
#define H_ERR ERROR
|
||||
#define H_nERR n(ERROR)
|
||||
#define H_ACK nACK
|
||||
#define H_nACK n(nACK)
|
||||
#define H_FLT nFAULT
|
||||
#define H_nFLT n(nFAULT)
|
||||
#define H_SELIN n(SELECTIN)
|
||||
#define H_nSELIN SELECTIN
|
||||
#define H_INIT nINIT
|
||||
#define H_nINIT n(nINIT)
|
||||
|
||||
/*
|
||||
* Microcode to execute very fast I/O sequences at the lowest bus level.
|
||||
*/
|
||||
|
||||
#define trig_d_pulse MS_TRIG(MS_REG_CTR,5,(int)d_pulse)
|
||||
char d_pulse[] = {
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,
|
||||
H_nAUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE, VP0_PULSE,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE
|
||||
};
|
||||
|
||||
#define trig_c_pulse MS_TRIG(MS_REG_CTR,5,(int)c_pulse)
|
||||
char c_pulse[] = {
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, 0,
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE, 0,
|
||||
H_nAUTO | H_SELIN | H_INIT | H_STROBE, VP0_PULSE,
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE, 0,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE, VP0_PULSE
|
||||
};
|
||||
|
||||
struct ppb_microseq disconnect_microseq[] = {
|
||||
MS_DASS(0x0), trig_d_pulse, MS_DASS(0x3c), trig_d_pulse,
|
||||
MS_DASS(0x20), trig_d_pulse, MS_DASS(0xf), trig_d_pulse, MS_RET(0)
|
||||
};
|
||||
|
||||
struct ppb_microseq connect_epp_microseq[] = {
|
||||
MS_DASS(0x0), trig_c_pulse, MS_DASS(0x3c), trig_c_pulse,
|
||||
MS_DASS(0x20), trig_c_pulse, MS_DASS(0xcf), trig_c_pulse, MS_RET(0)
|
||||
};
|
||||
|
||||
struct ppb_microseq connect_spp_microseq[] = {
|
||||
MS_DASS(0x0), trig_c_pulse, MS_DASS(0x3c), trig_c_pulse,
|
||||
MS_DASS(0x20), trig_c_pulse, MS_DASS(0x8f), trig_c_pulse, MS_RET(0)
|
||||
};
|
||||
|
||||
/*
|
||||
* nibble_inbyte_hook()
|
||||
*
|
||||
* Formats high and low nibble into a character
|
||||
*/
|
||||
static int
|
||||
nibble_inbyte_hook (void *p, char *ptr)
|
||||
{
|
||||
struct vpo_nibble *s = (struct vpo_nibble *)p;
|
||||
|
||||
/* increment the buffer pointer */
|
||||
*ptr++ = ((s->l >> 4) & 0x0f) + (s->h & 0xf0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Macro used to initialize each vpoio_data structure during
|
||||
* low level attachment
|
||||
*/
|
||||
#define INIT_NIBBLE_INBYTE_SUBMICROSEQ(vpo) { \
|
||||
(vpo)->vpo_nibble_inbyte_msq[2].arg[2].p = \
|
||||
(void *)&(vpo)->vpo_nibble.h; \
|
||||
(vpo)->vpo_nibble_inbyte_msq[4].arg[2].p = \
|
||||
(void *)&(vpo)->vpo_nibble.l; \
|
||||
(vpo)->vpo_nibble_inbyte_msq[5].arg[0].f = \
|
||||
nibble_inbyte_hook; \
|
||||
(vpo)->vpo_nibble_inbyte_msq[5].arg[1].p = \
|
||||
(void *)&(vpo)->vpo_nibble; \
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the sub-microseqence for MS_GET in NIBBLE mode
|
||||
* Retrieve the two nibbles and call the C function to generate the character
|
||||
* and store it in the buffer (see nibble_inbyte_hook())
|
||||
*/
|
||||
struct ppb_microseq nibble_inbyte_submicroseq[] = {
|
||||
|
||||
/* loop: */
|
||||
MS_CASS( H_AUTO | H_SELIN | H_INIT | H_STROBE),
|
||||
MS_DELAY(VP0_PULSE),
|
||||
MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* high nibble */),
|
||||
MS_CASS(H_nAUTO | H_SELIN | H_INIT | H_STROBE),
|
||||
MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* low nibble */),
|
||||
|
||||
/* do a C call to format the received nibbles */
|
||||
MS_C_CALL(MS_UNKNOWN /* C hook */, MS_UNKNOWN /* param */),
|
||||
MS_DBRA(-6 /* loop */),
|
||||
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the sub-microseqence for MS_GET in PS2 mode
|
||||
*/
|
||||
struct ppb_microseq ps2_inbyte_submicroseq[] = {
|
||||
MS_CASS(PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE),
|
||||
|
||||
/* loop: */
|
||||
MS_RFETCH_P(1, MS_REG_DTR, MS_FETCH_ALL),
|
||||
MS_CASS(PCD | H_nAUTO | H_SELIN | H_INIT | H_nSTROBE),
|
||||
MS_CASS(PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE),
|
||||
MS_DBRA(-3 /* loop */),
|
||||
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the sub-microsequence for MS_PUT in both NIBBLE and PS2 modes
|
||||
*/
|
||||
struct ppb_microseq spp_outbyte_submicroseq[] = {
|
||||
|
||||
/* loop: */
|
||||
MS_RASSERT_P(1, MS_REG_DTR),
|
||||
MS_CASS(H_nAUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_DELAY(VP0_PULSE),
|
||||
MS_DBRA(-4 /* loop */),
|
||||
|
||||
/* return from the put call */
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/* EPP 1.7 microsequences, ptr and len set at runtime */
|
||||
struct ppb_microseq epp17_outstr_body[] = {
|
||||
MS_CASS(H_AUTO | H_SELIN | H_INIT | H_STROBE),
|
||||
|
||||
/* loop: */
|
||||
MS_RASSERT_P(1, MS_REG_EPP),
|
||||
MS_BRSET(TIMEOUT, 4 /* error */), /* EPP timeout? */
|
||||
MS_DBRA(-2 /* loop */),
|
||||
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(0),
|
||||
/* error: */
|
||||
MS_CASS(H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(1)
|
||||
};
|
||||
|
||||
struct ppb_microseq epp17_instr_body[] = {
|
||||
MS_CASS(PCD | H_AUTO | H_SELIN | H_INIT | H_STROBE),
|
||||
|
||||
/* loop: */
|
||||
MS_RFETCH_P(1, MS_REG_EPP, MS_FETCH_ALL),
|
||||
MS_BRSET(TIMEOUT, 4 /* error */), /* EPP timeout? */
|
||||
MS_DBRA(-2 /* loop */),
|
||||
|
||||
MS_CASS(PCD | H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(0),
|
||||
/* error: */
|
||||
MS_CASS(PCD | H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_RET(1)
|
||||
};
|
||||
|
||||
static int
|
||||
vpoio_disconnect(struct vpoio_data *vpo)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ppb_MS_microseq(&vpo->vpo_dev, disconnect_microseq, &ret);
|
||||
return (ppb_release_bus(&vpo->vpo_dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* how : PPB_WAIT or PPB_DONTWAIT
|
||||
*/
|
||||
static int
|
||||
vpoio_connect(struct vpoio_data *vpo, int how)
|
||||
{
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
if ((error = ppb_request_bus(&vpo->vpo_dev, how)))
|
||||
return error;
|
||||
|
||||
if (PPB_IN_EPP_MODE(&vpo->vpo_dev))
|
||||
ppb_MS_microseq(&vpo->vpo_dev, connect_epp_microseq, &ret);
|
||||
else
|
||||
ppb_MS_microseq(&vpo->vpo_dev, connect_spp_microseq, &ret);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_in_disk_mode()
|
||||
*
|
||||
* Check if we are in disk mode
|
||||
*
|
||||
* XXX should be ported to microseq with MS_ASSERT()
|
||||
*/
|
||||
static int
|
||||
vpoio_in_disk_mode(struct vpoio_data *vpo)
|
||||
{
|
||||
|
||||
/* first, set H_AUTO high */
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
|
||||
/* when H_AUTO is set low, H_FLT should be high */
|
||||
ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) == 0)
|
||||
return (0);
|
||||
|
||||
/* when H_AUTO is set high, H_FLT should be low */
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) != 0)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_reset()
|
||||
*
|
||||
* SCSI reset signal, the drive must be in disk mode
|
||||
*
|
||||
* XXX should be ported to microseq with MS_TRIG()
|
||||
*/
|
||||
static void
|
||||
vpoio_reset (struct vpoio_data *vpo)
|
||||
{
|
||||
|
||||
/*
|
||||
* SCSI reset signal.
|
||||
*/
|
||||
ppb_wdtr(&vpo->vpo_dev, (1 << VP0_INITIATOR));
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE);
|
||||
DELAY(25);
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_detect()
|
||||
*
|
||||
* Detect and initialise the VP0 adapter.
|
||||
*/
|
||||
int
|
||||
vpoio_detect(struct vpoio_data *vpo)
|
||||
{
|
||||
|
||||
vpoio_disconnect(vpo);
|
||||
vpoio_connect(vpo, PPB_DONTWAIT);
|
||||
|
||||
if (!vpoio_in_disk_mode(vpo)) {
|
||||
vpoio_disconnect(vpo);
|
||||
return (VP0_EINITFAILED);
|
||||
}
|
||||
|
||||
/* send SCSI reset signal */
|
||||
vpoio_reset(vpo);
|
||||
|
||||
vpoio_disconnect(vpo);
|
||||
|
||||
if (vpoio_in_disk_mode(vpo))
|
||||
return (VP0_EINITFAILED);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_outstr()
|
||||
*/
|
||||
static int
|
||||
vpoio_outstr(struct vpoio_data *vpo, char *buffer, int size)
|
||||
{
|
||||
|
||||
int error = 0;
|
||||
|
||||
ppb_MS_exec(&vpo->vpo_dev, MS_OP_PUT, buffer, size, MS_UNKNOWN, &error);
|
||||
|
||||
#if 0
|
||||
/* XXX EPP 1.9 not implemented with microsequences */
|
||||
else {
|
||||
|
||||
ppb_reset_epp_timeout(&vpo->vpo_dev);
|
||||
ppb_wctr(&vpo->vpo_dev,
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE);
|
||||
|
||||
if (((long) buffer | size) & 0x03)
|
||||
ppb_outsb_epp(&vpo->vpo_dev,
|
||||
buffer, size);
|
||||
else
|
||||
ppb_outsl_epp(&vpo->vpo_dev,
|
||||
buffer, size/4);
|
||||
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
|
||||
error = VP0_EPPDATA_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ppb_wctr(&vpo->vpo_dev,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
}
|
||||
/* ppb_ecp_sync(&vpo->vpo_dev); */
|
||||
#endif
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_instr()
|
||||
*/
|
||||
static int
|
||||
vpoio_instr(struct vpoio_data *vpo, char *buffer, int size)
|
||||
{
|
||||
|
||||
register int k;
|
||||
int error = 0;
|
||||
int r, mode, epp;
|
||||
|
||||
ppb_MS_exec(&vpo->vpo_dev, MS_OP_GET, buffer, size, MS_UNKNOWN, &error);
|
||||
|
||||
#if 0
|
||||
/* XXX EPP 1.9 not implemented with microsequences */
|
||||
else {
|
||||
|
||||
ppb_reset_epp_timeout(&vpo->vpo_dev);
|
||||
ppb_wctr(&vpo->vpo_dev, PCD |
|
||||
H_AUTO | H_SELIN | H_INIT | H_STROBE);
|
||||
|
||||
if (((long) buffer | size) & 0x03)
|
||||
ppb_insb_epp(&vpo->vpo_dev,
|
||||
buffer, size);
|
||||
else
|
||||
ppb_insl_epp(&vpo->vpo_dev,
|
||||
buffer, size/4);
|
||||
|
||||
if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
|
||||
error = VP0_EPPDATA_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ppb_wctr(&vpo->vpo_dev, PCD |
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
}
|
||||
/* ppb_ecp_sync(&vpo->vpo_dev); */
|
||||
#endif
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static char
|
||||
vpoio_select(struct vpoio_data *vpo, int initiator, int target)
|
||||
{
|
||||
register int k;
|
||||
int ret;
|
||||
|
||||
struct ppb_microseq select_microseq[] = {
|
||||
|
||||
/* parameter list
|
||||
*/
|
||||
#define SELECT_TARGET MS_PARAM(0, 1, MS_TYP_INT)
|
||||
#define SELECT_INITIATOR MS_PARAM(3, 1, MS_TYP_INT)
|
||||
|
||||
/* send the select command to the drive */
|
||||
MS_DASS(MS_UNKNOWN),
|
||||
MS_CASS(H_nAUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_CASS( H_AUTO | H_nSELIN | H_INIT | H_STROBE),
|
||||
MS_DASS(MS_UNKNOWN),
|
||||
MS_CASS( H_AUTO | H_nSELIN | H_nINIT | H_STROBE),
|
||||
|
||||
/* now, wait until the drive is ready */
|
||||
MS_SET(VP0_SELTMO),
|
||||
/* loop: */ MS_BRSET(H_ACK, 3 /* ready */),
|
||||
MS_DBRA(-1 /* loop */),
|
||||
/* error: */ MS_RET(1),
|
||||
/* ready: */ MS_RET(0)
|
||||
};
|
||||
|
||||
/* initialize the select microsequence */
|
||||
ppb_MS_init_msq(select_microseq, 2,
|
||||
SELECT_TARGET, 1 << target,
|
||||
SELECT_INITIATOR, 1 << initiator);
|
||||
|
||||
ppb_MS_microseq(&vpo->vpo_dev, select_microseq, &ret);
|
||||
|
||||
if (ret)
|
||||
return (VP0_ESELECT_TIMEOUT);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_wait()
|
||||
*
|
||||
* H_SELIN must be low.
|
||||
*
|
||||
* XXX should be ported to microseq
|
||||
*/
|
||||
static char
|
||||
vpoio_wait(struct vpoio_data *vpo, int tmo)
|
||||
{
|
||||
|
||||
register int k;
|
||||
register char r;
|
||||
|
||||
#if 0 /* broken */
|
||||
if (ppb_poll_device(&vpo->vpo_dev, 150, nBUSY, nBUSY, PPB_INTR))
|
||||
return (0);
|
||||
|
||||
return (ppb_rstr(&vpo->vpo_dev) & 0xf0);
|
||||
#endif
|
||||
|
||||
/* XXX should be ported to microseq */
|
||||
k = 0;
|
||||
while (!((r = ppb_rstr(&vpo->vpo_dev)) & nBUSY) && (k++ < tmo))
|
||||
;
|
||||
|
||||
/*
|
||||
* Return some status information.
|
||||
* Semantics : 0xc0 = ZIP wants more data
|
||||
* 0xd0 = ZIP wants to send more data
|
||||
* 0xe0 = ZIP wants command
|
||||
* 0xf0 = end of transfer, ZIP is sending status
|
||||
*/
|
||||
if (k < tmo)
|
||||
return (r & 0xf0);
|
||||
|
||||
return (0); /* command timed out */
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_probe()
|
||||
*
|
||||
* Low level probe of vpo device
|
||||
*
|
||||
*/
|
||||
struct ppb_device *
|
||||
vpoio_probe(struct ppb_data *ppb, struct vpoio_data *vpo)
|
||||
{
|
||||
|
||||
/* ppbus dependent initialisation */
|
||||
vpo->vpo_dev.id_unit = vpo->vpo_unit;
|
||||
vpo->vpo_dev.name = "vpo";
|
||||
vpo->vpo_dev.ppb = ppb;
|
||||
|
||||
/* now, try to initialise the drive */
|
||||
if (vpoio_detect(vpo)) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (&vpo->vpo_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_attach()
|
||||
*
|
||||
* Low level attachment of vpo device
|
||||
*
|
||||
*/
|
||||
int
|
||||
vpoio_attach(struct vpoio_data *vpo)
|
||||
{
|
||||
int epp;
|
||||
|
||||
/*
|
||||
* Report ourselves
|
||||
*/
|
||||
printf("vpo%d: <Iomega VPI0 Parallel to SCSI adapter> on ppbus %d\n",
|
||||
vpo->vpo_dev.id_unit, vpo->vpo_dev.ppb->ppb_link->adapter_unit);
|
||||
|
||||
/*
|
||||
* Initialize microsequence code
|
||||
*/
|
||||
vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc(
|
||||
sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT);
|
||||
|
||||
if (!vpo->vpo_nibble_inbyte_msq)
|
||||
return (0);
|
||||
|
||||
bcopy((void *)nibble_inbyte_submicroseq,
|
||||
(void *)vpo->vpo_nibble_inbyte_msq,
|
||||
sizeof(nibble_inbyte_submicroseq));
|
||||
|
||||
INIT_NIBBLE_INBYTE_SUBMICROSEQ(vpo);
|
||||
|
||||
/*
|
||||
* Initialize mode dependent in/out microsequences
|
||||
*/
|
||||
ppb_request_bus(&vpo->vpo_dev, PPB_WAIT);
|
||||
|
||||
/* enter NIBBLE mode to configure submsq */
|
||||
if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1) {
|
||||
|
||||
ppb_MS_GET_init(&vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
|
||||
|
||||
ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq);
|
||||
}
|
||||
|
||||
/* enter PS2 mode to configure submsq */
|
||||
if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1) {
|
||||
|
||||
ppb_MS_GET_init(&vpo->vpo_dev, ps2_inbyte_submicroseq);
|
||||
|
||||
ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq);
|
||||
}
|
||||
|
||||
epp = ppb_get_epp_protocol(&vpo->vpo_dev);
|
||||
|
||||
/* enter EPP mode to configure submsq */
|
||||
if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) {
|
||||
|
||||
switch (epp) {
|
||||
case EPP_1_9:
|
||||
/* XXX EPP 1.9 support should be improved */
|
||||
case EPP_1_7:
|
||||
ppb_MS_GET_init(&vpo->vpo_dev, epp17_instr_body);
|
||||
|
||||
ppb_MS_PUT_init(&vpo->vpo_dev, epp17_outstr_body);
|
||||
break;
|
||||
default:
|
||||
panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
|
||||
epp);
|
||||
}
|
||||
}
|
||||
|
||||
/* try to enter EPP or PS/2 mode, NIBBLE otherwise */
|
||||
if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) {
|
||||
switch (epp) {
|
||||
case EPP_1_9:
|
||||
printf("vpo%d: EPP 1.9 mode\n", vpo->vpo_unit);
|
||||
break;
|
||||
case EPP_1_7:
|
||||
printf("vpo%d: EPP 1.7 mode\n", vpo->vpo_unit);
|
||||
break;
|
||||
default:
|
||||
panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
|
||||
epp);
|
||||
}
|
||||
} else if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1)
|
||||
printf("vpo%d: PS2 mode\n", vpo->vpo_unit);
|
||||
|
||||
else if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1)
|
||||
printf("vpo%d: NIBBLE mode\n", vpo->vpo_unit);
|
||||
|
||||
else {
|
||||
printf("vpo%d: can't enter NIBBLE, PS2 or EPP mode\n",
|
||||
vpo->vpo_unit);
|
||||
|
||||
ppb_release_bus(&vpo->vpo_dev);
|
||||
|
||||
free(vpo->vpo_nibble_inbyte_msq, M_DEVBUF);
|
||||
return (0);
|
||||
}
|
||||
|
||||
ppb_release_bus(&vpo->vpo_dev);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_reset_bus()
|
||||
*
|
||||
*/
|
||||
int
|
||||
vpoio_reset_bus(struct vpoio_data *vpo)
|
||||
{
|
||||
/* first, connect to the drive */
|
||||
if (vpoio_connect(vpo, PPB_WAIT|PPB_INTR) ||
|
||||
(vpoio_in_disk_mode(vpo) == 0)) {
|
||||
|
||||
/* release ppbus */
|
||||
vpoio_disconnect(vpo);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* reset the SCSI bus */
|
||||
vpoio_reset(vpo);
|
||||
|
||||
/* then disconnect */
|
||||
vpoio_disconnect(vpo);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpoio_do_scsi()
|
||||
*
|
||||
* Send an SCSI command
|
||||
*
|
||||
*/
|
||||
int
|
||||
vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,
|
||||
int clen, char *buffer, int blen, int *result, int *count,
|
||||
int *ret)
|
||||
{
|
||||
|
||||
register char r;
|
||||
char l, h = 0;
|
||||
int len, error = 0;
|
||||
register int k;
|
||||
|
||||
/*
|
||||
* enter disk state, allocate the ppbus
|
||||
*
|
||||
* XXX
|
||||
* Should we allow this call to be interruptible?
|
||||
* The only way to report the interruption is to return
|
||||
* EIO do upper SCSI code :^(
|
||||
*/
|
||||
if ((error = vpoio_connect(vpo, PPB_WAIT|PPB_INTR)))
|
||||
return (error);
|
||||
|
||||
if (!vpoio_in_disk_mode(vpo)) {
|
||||
*ret = VP0_ECONNECT; goto error;
|
||||
}
|
||||
|
||||
if ((*ret = vpoio_select(vpo,host,target)))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Send the command ...
|
||||
*
|
||||
* set H_SELIN low for vpoio_wait().
|
||||
*/
|
||||
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
|
||||
for (k = 0; k < clen; k++) {
|
||||
if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) {
|
||||
*ret = VP0_ECMD_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
if (vpoio_outstr(vpo, &command[k], 1)) {
|
||||
*ret = VP0_EPPDATA_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Completion ...
|
||||
*/
|
||||
|
||||
*count = 0;
|
||||
for (;;) {
|
||||
|
||||
if (!(r = vpoio_wait(vpo, VP0_LOW_SPINTMO))) {
|
||||
*ret = VP0_ESTATUS_TIMEOUT; goto error;
|
||||
}
|
||||
|
||||
/* stop when the ZIP wants to send status */
|
||||
if (r == (char)0xf0)
|
||||
break;
|
||||
|
||||
if (*count >= blen) {
|
||||
*ret = VP0_EDATA_OVERFLOW;
|
||||
goto error;
|
||||
}
|
||||
len = (((blen - *count) >= VP0_SECTOR_SIZE)) ?
|
||||
VP0_SECTOR_SIZE : 1;
|
||||
|
||||
/* ZIP wants to send data? */
|
||||
if (r == (char)0xc0)
|
||||
error = vpoio_outstr(vpo, &buffer[*count], len);
|
||||
else
|
||||
error = vpoio_instr(vpo, &buffer[*count], len);
|
||||
|
||||
if (error) {
|
||||
*ret = error;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*count += len;
|
||||
}
|
||||
|
||||
if (vpoio_instr(vpo, &l, 1)) {
|
||||
*ret = VP0_EOTHER; goto error;
|
||||
}
|
||||
|
||||
/* check if the ZIP wants to send more status */
|
||||
if (vpoio_wait(vpo, VP0_FAST_SPINTMO) == (char)0xf0)
|
||||
if (vpoio_instr(vpo, &h, 1)) {
|
||||
*ret = VP0_EOTHER+2; goto error;
|
||||
}
|
||||
|
||||
*result = ((int) h << 8) | ((int) l & 0xff);
|
||||
|
||||
error:
|
||||
/* return to printer state, release the ppbus */
|
||||
vpoio_disconnect(vpo);
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Nicolas Souchu
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -23,21 +23,17 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: vpo.h,v 1.1 1997/08/14 13:57:45 msmith Exp $
|
||||
* $Id: vpoio.h,v 1.1.2.3 1998/06/14 15:37:21 son Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __VP03_H
|
||||
#define __VP03_H
|
||||
|
||||
#define barrier() __asm__("": : :"memory")
|
||||
#ifndef __VP0IO_H
|
||||
#define __VP0IO_H
|
||||
|
||||
/*
|
||||
* The ZIP drive cannot act as an initiator.
|
||||
*/
|
||||
#define VP0_INITIATOR 0x7
|
||||
|
||||
#define VP0_SECTOR_SIZE 512
|
||||
#define VP0_BUFFER_SIZE 0x12000
|
||||
|
||||
#define VP0_SPL() splbio()
|
||||
|
||||
#define VP0_ESELECT_TIMEOUT 1
|
||||
#define VP0_ECMD_TIMEOUT 2
|
||||
#define VP0_ECONNECT 3
|
||||
|
|
@ -53,58 +49,36 @@
|
|||
|
||||
#define VP0_OPENNINGS 1
|
||||
|
||||
#define n(flags) (~(flags) & (flags))
|
||||
|
||||
/*
|
||||
* VP0 timings.
|
||||
* Data structure used during microsequence execution
|
||||
* when characters are received in nibble mode
|
||||
*/
|
||||
#define MHZ_16_IO_DURATION 62
|
||||
|
||||
#define VP0_SPP_WRITE_PULSE 253
|
||||
#define VP0_NIBBLE_READ_PULSE 486
|
||||
|
||||
/*
|
||||
* VP0 connections.
|
||||
*/
|
||||
#define H_AUTO n(AUTOFEED)
|
||||
#define H_nAUTO AUTOFEED
|
||||
#define H_STROBE n(STROBE)
|
||||
#define H_nSTROBE STROBE
|
||||
#define H_BSY n(nBUSY)
|
||||
#define H_nBSY n_BUSY
|
||||
#define H_SEL SELECT
|
||||
#define H_nSEL n(SELECT)
|
||||
#define H_ERR ERROR
|
||||
#define H_nERR n(ERROR)
|
||||
#define H_ACK nACK
|
||||
#define H_nACK n(nACK)
|
||||
#define H_FLT nFAULT
|
||||
#define H_nFLT n(nFAULT)
|
||||
#define H_SELIN n(SELECTIN)
|
||||
#define H_nSELIN SELECTIN
|
||||
#define H_INIT nINIT
|
||||
#define H_nINIT n(nINIT)
|
||||
|
||||
struct vpo_sense {
|
||||
struct scsi_sense cmd;
|
||||
unsigned int stat;
|
||||
unsigned int count;
|
||||
struct vpo_nibble {
|
||||
char h; /* most significant nibble */
|
||||
char l; /* less significant nibble */
|
||||
};
|
||||
|
||||
struct vpo_data {
|
||||
unsigned short vpo_unit;
|
||||
struct vpoio_data {
|
||||
unsigned short int vpo_unit;
|
||||
|
||||
int vpo_stat;
|
||||
int vpo_count;
|
||||
int vpo_error;
|
||||
struct vpo_nibble vpo_nibble;
|
||||
|
||||
struct ppb_status vpo_status;
|
||||
struct vpo_sense vpo_sense;
|
||||
|
||||
unsigned char vpo_buffer[VP0_BUFFER_SIZE];
|
||||
/* each device must have its own nibble inbyte microsequence */
|
||||
struct ppb_microseq *vpo_nibble_inbyte_msq;
|
||||
|
||||
struct ppb_device vpo_dev;
|
||||
struct scsi_link sc_link;
|
||||
};
|
||||
|
||||
#define vpoio_set_unit(vpo,unit) ((vpo)->vpo_unit = unit)
|
||||
|
||||
struct ppb_device *vpoio_probe(struct ppb_data *ppb, struct vpoio_data *vpo);
|
||||
|
||||
int vpoio_attach(struct vpoio_data *vpo);
|
||||
int vpoio_detect(struct vpoio_data *vpo);
|
||||
int vpoio_reset_bus(struct vpoio_data *vpo);
|
||||
|
||||
int vpoio_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,
|
||||
int clen, char *buffer, int blen, int *result, int *count,
|
||||
int *ret);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Nicolas Souchu
|
||||
* Copyright (c) 1997, 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppc.c,v 1.2 1997/09/01 02:08:41 bde Exp $
|
||||
* $Id: ppc.c,v 1.3 1998/04/17 22:36:37 des Exp $
|
||||
*
|
||||
*/
|
||||
#include "ppc.h"
|
||||
|
|
@ -44,6 +44,8 @@
|
|||
#include <i386/isa/isa_device.h>
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
|
||||
#include <i386/isa/ppcreg.h>
|
||||
|
||||
static int ppcprobe(struct isa_device *);
|
||||
|
|
@ -57,14 +59,26 @@ static struct ppc_data *ppcdata[NPPC];
|
|||
static int nppc = 0;
|
||||
|
||||
static char *ppc_types[] = {
|
||||
"SMC", "SMC FDC37C665GT", "SMC FDC37C666GT",
|
||||
"NatSemi", "PC87332", "PC87306",
|
||||
"Intel 82091AA", "Generic", 0
|
||||
"SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306",
|
||||
"82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0
|
||||
};
|
||||
|
||||
/* list of available modes */
|
||||
static char *ppc_avms[] = {
|
||||
"COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only",
|
||||
"EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only",
|
||||
"ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP",
|
||||
"ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0
|
||||
};
|
||||
|
||||
/* list of current executing modes
|
||||
* Note that few modes do not actually exist.
|
||||
*/
|
||||
static char *ppc_modes[] = {
|
||||
"AUTODETECT", "NIBBLE", "PS/2", "EPP", "ECP+EPP", "ECP+PS/2", "ECP",
|
||||
"UNKNOWN", 0
|
||||
"COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP",
|
||||
"EPP", "EPP", "EPP", "ECP",
|
||||
"ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP",
|
||||
"ECP+EPP", "ECP+EPP", "ECP+EPP", 0
|
||||
};
|
||||
|
||||
static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 };
|
||||
|
|
@ -110,12 +124,19 @@ static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); }
|
|||
static void ppc_reset_epp_timeout(int);
|
||||
static void ppc_ecp_sync(int);
|
||||
|
||||
static int ppc_exec_microseq(int, struct ppb_microseq *, int *);
|
||||
static int ppc_generic_setmode(int, int);
|
||||
|
||||
static struct ppb_adapter ppc_adapter = {
|
||||
|
||||
0, /* no intr handler, filled by chipset dependent code */
|
||||
|
||||
ppc_reset_epp_timeout, ppc_ecp_sync,
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_generic_setmode,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
|
||||
|
|
@ -143,8 +164,8 @@ ppc_ecp_sync(int unit) {
|
|||
DELAY(100);
|
||||
}
|
||||
|
||||
printf("ppc: ECP sync failed as data still " \
|
||||
"present in FIFO.\n");
|
||||
printf("ppc%d: ECP sync failed as data still " \
|
||||
"present in FIFO.\n", unit);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -158,6 +179,35 @@ ppcintr(int unit)
|
|||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ppc_ecp_config(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (chipset_mode & PPB_EPP)
|
||||
/* select EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
else if (chipset_mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
else
|
||||
/* keep ECP mode alone, default for NIBBLE */
|
||||
w_ecr(ppc, 0x70);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_detect_port(struct ppc_data *ppc)
|
||||
{
|
||||
|
||||
w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */
|
||||
w_dtr(ppc, 0xaa);
|
||||
if (r_dtr(ppc) != (char) 0xaa)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_pc873xx_detect
|
||||
*
|
||||
|
|
@ -170,11 +220,11 @@ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0};
|
|||
static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0};
|
||||
|
||||
static int
|
||||
ppc_pc873xx_detect(struct ppc_data *ppc)
|
||||
ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */
|
||||
{
|
||||
static int index = 0;
|
||||
int base, idport;
|
||||
int val, mode;
|
||||
int val;
|
||||
|
||||
while ((idport = pc873xx_basetab[index++])) {
|
||||
|
||||
|
|
@ -235,7 +285,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
printf("PC873xx locked\n");
|
||||
|
||||
/* work out what mode we're in */
|
||||
mode = PPB_NIBBLE; /* worst case */
|
||||
ppc->ppc_avm |= PPB_NIBBLE; /* worst case */
|
||||
|
||||
outb(idport, PC873_PCR);
|
||||
val = inb(idport + 1);
|
||||
|
|
@ -243,10 +293,10 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport, PC873_PTR);
|
||||
val = inb(idport + 1);
|
||||
if (!(val & PC873_EPPRDIR)) {
|
||||
mode = PPB_EPP; /* As we would have done it anwyay */
|
||||
ppc->ppc_avm |= PPB_EPP; /* As we would have done it anwyay */
|
||||
}
|
||||
} else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) {
|
||||
mode = PPB_PS2; /* tolerable alternative */
|
||||
ppc->ppc_avm |= PPB_PS2; /* tolerable alternative */
|
||||
}
|
||||
} else {
|
||||
if (bootverbose)
|
||||
|
|
@ -299,7 +349,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport + 1, val);
|
||||
|
||||
/* we are an EPP-32 port */
|
||||
mode = PPB_EPP;
|
||||
ppc->ppc_avm |= PPB_EPP;
|
||||
} else {
|
||||
if (bootverbose)
|
||||
printf("ECP\n");
|
||||
|
|
@ -309,44 +359,21 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK);
|
||||
|
||||
/* we look like a PS/2 port */
|
||||
mode = PPB_PS2;
|
||||
ppc->ppc_avm |= PPB_PS2;
|
||||
}
|
||||
}
|
||||
return(mode);
|
||||
|
||||
return(chipset_mode);
|
||||
}
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_detect_ps2(struct ppc_data *ppc)
|
||||
ppc_check_epp_timeout(struct ppc_data *ppc)
|
||||
{
|
||||
char save_control, r;
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
|
||||
save_control = r_ctr(ppc);
|
||||
|
||||
/* Try PS/2 mode */
|
||||
w_ctr(ppc, 0xec);
|
||||
w_dtr(ppc, 0x55);
|
||||
|
||||
/* needed if in ECP mode */
|
||||
if (ppc->ppc_mode == PPB_ECP)
|
||||
w_ctr(ppc, PCD | 0xec);
|
||||
r = r_dtr(ppc);
|
||||
|
||||
if (r != (char) 0xff) {
|
||||
if (r != (char) 0x55)
|
||||
return 0;
|
||||
|
||||
w_dtr(ppc, 0xaa);
|
||||
r = r_dtr(ppc);
|
||||
if (r != (char) 0xaa)
|
||||
return 0;
|
||||
|
||||
return (PPB_NIBBLE);
|
||||
} else
|
||||
w_ctr(ppc, save_control);
|
||||
|
||||
return (PPB_PS2);
|
||||
return (!(r_str(ppc) & TIMEOUT));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -355,11 +382,10 @@ ppc_detect_ps2(struct ppc_data *ppc)
|
|||
* SMC FDC37C66xGT configuration.
|
||||
*/
|
||||
static int
|
||||
ppc_smc37c66xgt_detect(struct ppc_data *ppc, int mode)
|
||||
ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
int s, i;
|
||||
char r;
|
||||
int retry = 0; /* boolean */
|
||||
int type = -1;
|
||||
int csr = SMC66x_CSR; /* initial value is 0x3F0 */
|
||||
|
||||
|
|
@ -404,7 +430,7 @@ config:
|
|||
* If chipset not found, do not continue.
|
||||
*/
|
||||
if (type == -1)
|
||||
return (0);
|
||||
return (-1);
|
||||
|
||||
/* select CR1 */
|
||||
outb(csr, 0x1);
|
||||
|
|
@ -412,65 +438,72 @@ config:
|
|||
/* read the port's address: bits 0 and 1 of CR1 */
|
||||
r = inb(cio) & SMC_CR1_ADDR;
|
||||
if (port_address[r] != ppc->ppc_base)
|
||||
return (0);
|
||||
return (-1);
|
||||
|
||||
ppc->ppc_type = type;
|
||||
|
||||
/*
|
||||
* CR1 and CR4 registers bits 3 and 0/1 for mode configuration
|
||||
* If SPP mode is detected, try to set ECP+EPP mode end retry
|
||||
* detection to verify.
|
||||
* If SPP mode is detected, try to set ECP+EPP mode
|
||||
*/
|
||||
|
||||
retry:
|
||||
/* select CR1 register */
|
||||
if (bootverbose) {
|
||||
outb(csr, 0x1);
|
||||
printf("SMC registers CR1=0x%x", ppc->ppc_unit,
|
||||
inb(cio) & 0xff);
|
||||
|
||||
outb(csr, 0x4);
|
||||
printf(" CR4=0x%x", inb(cio) & 0xff);
|
||||
}
|
||||
|
||||
/* select CR1 */
|
||||
outb(csr, 0x1);
|
||||
|
||||
if (!mode) {
|
||||
if (!chipset_mode) {
|
||||
/* autodetect mode */
|
||||
|
||||
/* 666GT chipset is hardwired to an extended mode */
|
||||
if (type == SMC_37C666GT)
|
||||
mode = PPB_ECP_EPP;
|
||||
/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
|
||||
if (type == SMC_37C666GT) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
|
||||
else if ((inb(cio) & SMC_CR1_MODE) == 0) {
|
||||
} else
|
||||
if ((inb(cio) & SMC_CR1_MODE) == 0) {
|
||||
/* already in extended parallel port mode, read CR4 */
|
||||
outb(csr, 0x4);
|
||||
r = (inb(cio) & SMC_CR4_EMODE);
|
||||
|
||||
switch (r) {
|
||||
case SMC_SPP:
|
||||
/* let's detect NIBBLE or PS/2 later */
|
||||
ppc->ppc_avm |= PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_EPPSPP:
|
||||
mode = PPB_EPP;
|
||||
ppc->ppc_avm |= PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_ECP:
|
||||
/*
|
||||
* Yet, don't know what to do with it! XXX
|
||||
* So, consider ECP mode as PS/2.
|
||||
* (see configuration later).
|
||||
*/
|
||||
mode = PPB_ECP;
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_ECPEPP:
|
||||
mode = PPB_ECP_EPP;
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* not an extended port mode */
|
||||
ppc->ppc_avm |= PPB_SPP;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* mode forced */
|
||||
|
||||
/* 666GT chipset is hardwired to an extended mode */
|
||||
/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
|
||||
if (type == SMC_37C666GT)
|
||||
goto end_detect;
|
||||
|
||||
r = inb(cio);
|
||||
if (mode == PPB_NIBBLE || mode == PPB_PS2) {
|
||||
/* do not use ECP when the mode is forced to SPP */
|
||||
if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) {
|
||||
/* do not use ECP when the mode is not forced to */
|
||||
outb(cio, r | SMC_CR1_MODE);
|
||||
} else {
|
||||
/* an extended mode is selected */
|
||||
|
|
@ -480,30 +513,26 @@ retry:
|
|||
outb(csr, 0x4);
|
||||
r = inb(cio) & ~SMC_CR4_EMODE;
|
||||
|
||||
switch (mode) {
|
||||
case PPB_EPP:
|
||||
if (chipset_mode & PPB_ECP) {
|
||||
if (chipset_mode & PPB_EPP) {
|
||||
outb(cio, r | SMC_ECPEPP);
|
||||
} else {
|
||||
outb(cio, r | SMC_ECP);
|
||||
}
|
||||
} else {
|
||||
/* PPB_EPP is set */
|
||||
outb(cio, r | SMC_EPPSPP);
|
||||
break;
|
||||
|
||||
case PPB_ECP:
|
||||
case PPB_ECP_PS2:
|
||||
outb(cio, r | SMC_ECP);
|
||||
break;
|
||||
|
||||
case PPB_ECP_EPP:
|
||||
outb(cio, r | SMC_ECPEPP);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("ppc: unknown mode (%d)\n",
|
||||
mode);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
end_detect:
|
||||
if (PPB_IS_EPP(mode)) {
|
||||
|
||||
if (bootverbose)
|
||||
printf ("\n");
|
||||
|
||||
if (chipset_mode & PPB_EPP) {
|
||||
/* select CR4 */
|
||||
outb(csr, 0x4);
|
||||
r = inb(cio);
|
||||
|
|
@ -511,11 +540,9 @@ end_detect:
|
|||
/*
|
||||
* Set the EPP protocol...
|
||||
* Low=EPP 1.9 (1284 standard) and High=EPP 1.7
|
||||
* ...then check the result.
|
||||
*/
|
||||
if (ppc->ppc_epp == EPP_1_9)
|
||||
outb(cio, (r & ~SMC_CR4_EPPTYPE));
|
||||
|
||||
else
|
||||
outb(cio, (r | SMC_CR4_EPPTYPE));
|
||||
}
|
||||
|
|
@ -523,86 +550,214 @@ end_detect:
|
|||
/* end config mode */
|
||||
outb(csr, 0xaa);
|
||||
|
||||
/*
|
||||
* Write 100 to the mode bits and disable DMA, enable intr.
|
||||
*/
|
||||
if (mode == PPB_ECP_EPP)
|
||||
w_ecr(ppc, 0x80);
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
/*
|
||||
* Write 001 to the mode bits and disable DMA, enable intr.
|
||||
*/
|
||||
if (mode == PPB_ECP)
|
||||
w_ecr(ppc, 0x20);
|
||||
|
||||
if (PPB_IS_EPP(mode)) {
|
||||
/*
|
||||
* Try to reset EPP timeout bit.
|
||||
* If it fails, try PS/2 and NIBBLE modes.
|
||||
*/
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT))
|
||||
return (mode);
|
||||
} else {
|
||||
if (mode)
|
||||
return (mode);
|
||||
}
|
||||
|
||||
/* detect PS/2 or NIBBLE mode */
|
||||
return (ppc_detect_ps2(ppc));
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Winbond W83877F stuff
|
||||
*
|
||||
* EFER: extended function enable register
|
||||
* EFIR: extended function index register
|
||||
* EFDR: extended function data register
|
||||
*/
|
||||
#define efir ((efer == 0x250) ? 0x251 : 0x3f0)
|
||||
#define efdr ((efer == 0x250) ? 0x252 : 0x3f1)
|
||||
|
||||
static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 };
|
||||
static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 };
|
||||
static int w83877f_keyiter[] = { 1, 2, 2, 1 };
|
||||
static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 };
|
||||
|
||||
static int
|
||||
ppc_check_ecpepp_timeout(struct ppc_data *ppc)
|
||||
ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
char r;
|
||||
int i, j, efer, base;
|
||||
unsigned char r, hefere, hefras;
|
||||
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
for (i = 0; i < 4; i ++) {
|
||||
/* first try to enable configuration registers */
|
||||
efer = w83877f_efers[i];
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT)) {
|
||||
return (PPB_ECP_EPP);
|
||||
/* write the key to the EFER */
|
||||
for (j = 0; j < w83877f_keyiter[i]; j ++)
|
||||
outb (efer, w83877f_keys[i]);
|
||||
|
||||
/* then check HEFERE and HEFRAS bits */
|
||||
outb (efir, 0x0c);
|
||||
hefere = inb(efdr) & WINB_HEFERE;
|
||||
|
||||
outb (efir, 0x16);
|
||||
hefras = inb(efdr) & WINB_HEFRAS;
|
||||
|
||||
/*
|
||||
* HEFRAS HEFERE
|
||||
* 0 1 write 89h to 250h (power-on default)
|
||||
* 1 0 write 86h twice to 3f0h
|
||||
* 1 1 write 87h twice to 3f0h
|
||||
* 0 0 write 88h to 250h
|
||||
*/
|
||||
if ((hefere | hefras) == w83877f_hefs[i])
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* If EPP timeout bit is not reset, DON'T use EPP */
|
||||
w_ecr(ppc, 0x20);
|
||||
return (-1); /* failed */
|
||||
|
||||
return (PPB_ECP_PS2);
|
||||
found:
|
||||
/* check base port address - read from CR23 */
|
||||
outb(efir, 0x23);
|
||||
if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */
|
||||
return (-1);
|
||||
|
||||
/* read CHIP ID from CR9/bits0-3 */
|
||||
outb(efir, 0x9);
|
||||
|
||||
switch (inb(efdr) & WINB_CHIPID) {
|
||||
case WINB_W83877F_ID:
|
||||
ppc->ppc_type = WINB_W83877F;
|
||||
break;
|
||||
|
||||
case WINB_W83877AF_ID:
|
||||
ppc->ppc_type = WINB_W83877AF;
|
||||
break;
|
||||
|
||||
default:
|
||||
ppc->ppc_type = WINB_UNKNOWN;
|
||||
}
|
||||
|
||||
if (bootverbose) {
|
||||
/* dump of registers */
|
||||
printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]);
|
||||
for (i = 0; i <= 0xd; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
for (i = 0x10; i <= 0x17; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
outb(efir, 0x1e);
|
||||
printf("0x%x ", inb(efdr));
|
||||
for (i = 0x20; i <= 0x29; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (!chipset_mode) {
|
||||
/* autodetect mode */
|
||||
|
||||
/* select CR0 */
|
||||
outb(efir, 0x0);
|
||||
r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1);
|
||||
|
||||
/* select CR9 */
|
||||
outb(efir, 0x9);
|
||||
r |= (inb(efdr) & WINB_PRTMODS2);
|
||||
|
||||
switch (r) {
|
||||
case WINB_W83757:
|
||||
if (bootverbose)
|
||||
printf("ppc%d: W83757 compatible mode\n",
|
||||
ppc->ppc_unit);
|
||||
return (-1); /* generic or SMC-like */
|
||||
|
||||
case WINB_EXTFDC:
|
||||
case WINB_EXTADP:
|
||||
case WINB_EXT2FDD:
|
||||
case WINB_JOYSTICK:
|
||||
if (bootverbose)
|
||||
printf("ppc%d: not in parallel port mode\n",
|
||||
ppc->ppc_unit);
|
||||
return (-1);
|
||||
|
||||
case (WINB_PARALLEL | WINB_EPP_SPP):
|
||||
ppc->ppc_avm |= PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case (WINB_PARALLEL | WINB_ECP):
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case (WINB_PARALLEL | WINB_ECP_EPP):
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
default:
|
||||
printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* mode forced */
|
||||
|
||||
/* select CR9 and set PRTMODS2 bit */
|
||||
outb(efir, 0x9);
|
||||
outb(efdr, inb(efdr) & ~WINB_PRTMODS2);
|
||||
|
||||
/* select CR0 and reset PRTMODSx bits */
|
||||
outb(efir, 0x0);
|
||||
outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1));
|
||||
|
||||
if (chipset_mode & PPB_ECP) {
|
||||
if (chipset_mode & PPB_EPP)
|
||||
outb(efdr, inb(efdr) | WINB_ECP_EPP);
|
||||
else
|
||||
outb(efdr, inb(efdr) | WINB_ECP);
|
||||
} else {
|
||||
/* select EPP_SPP otherwise */
|
||||
outb(efdr, inb(efdr) | WINB_EPP_SPP);
|
||||
}
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
/* exit configuration mode */
|
||||
outb(efer, 0xaa);
|
||||
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_generic_detect
|
||||
*/
|
||||
static int
|
||||
ppc_generic_detect(struct ppc_data *ppc, int mode)
|
||||
ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
char save_control, r;
|
||||
char save_control;
|
||||
|
||||
/* don't know what to do here */
|
||||
if (mode)
|
||||
return (mode);
|
||||
if (!chipset_mode) {
|
||||
/* first, check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
if ((r_ecr(ppc) & 0xe0) == 0x20) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
|
||||
/* try to reset EPP timeout bit */
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
/* search for SMC style ECP+EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
}
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT)) {
|
||||
return (PPB_EPP);
|
||||
}
|
||||
/* try to reset EPP timeout bit */
|
||||
if (ppc_check_epp_timeout(ppc)) {
|
||||
ppc->ppc_avm |= PPB_EPP;
|
||||
|
||||
/* Now check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
r = r_ecr(ppc);
|
||||
if ((r & 0xe0) == 0x20) {
|
||||
/* Search for SMC style EPP+ECP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
/* SMC like chipset found */
|
||||
ppc->ppc_type = SMC_LIKE;
|
||||
}
|
||||
|
||||
return (ppc_check_ecpepp_timeout(ppc));
|
||||
}
|
||||
/* XXX try to detect NIBBLE mode */
|
||||
ppc->ppc_avm |= PPB_NIBBLE;
|
||||
|
||||
return (ppc_detect_ps2(ppc));
|
||||
} else
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -611,22 +766,258 @@ ppc_generic_detect(struct ppc_data *ppc, int mode)
|
|||
* mode is the mode suggested at boot
|
||||
*/
|
||||
static int
|
||||
ppc_detect(struct ppc_data *ppc, int mode) {
|
||||
ppc_detect(struct ppc_data *ppc, int chipset_mode) {
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_pc873xx_detect(ppc)))
|
||||
goto end_detect;
|
||||
int i, mode;
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode =
|
||||
ppc_smc37c66xgt_detect(ppc, mode)))
|
||||
goto end_detect;
|
||||
/* list of supported chipsets */
|
||||
int (*chipset_detect[])(struct ppc_data *, int) = {
|
||||
ppc_pc873xx_detect,
|
||||
ppc_smc37c66xgt_detect,
|
||||
ppc_w83877f_detect,
|
||||
ppc_generic_detect,
|
||||
NULL
|
||||
};
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_generic_detect(ppc, mode)))
|
||||
goto end_detect;
|
||||
/* if can't find the port and mode not forced return error */
|
||||
if (!ppc_detect_port(ppc) && chipset_mode == 0)
|
||||
return (EIO); /* failed, port not present */
|
||||
|
||||
printf("ppc: port not present at 0x%x.\n", ppc->ppc_base);
|
||||
return (PPC_ENOPORT);
|
||||
/* assume centronics compatible mode is supported */
|
||||
ppc->ppc_avm = PPB_COMPATIBLE;
|
||||
|
||||
end_detect:
|
||||
/* we have to differenciate available chipset modes,
|
||||
* chipset running modes and IEEE-1284 operating modes
|
||||
*
|
||||
* after detection, the port must support running in compatible mode
|
||||
*/
|
||||
for (i=0; chipset_detect[i] != NULL; i++) {
|
||||
if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) {
|
||||
ppc->ppc_mode = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_exec_microseq()
|
||||
*
|
||||
* Execute a microsequence.
|
||||
* Microsequence mechanism is supposed to handle fast I/O operations.
|
||||
*/
|
||||
static int
|
||||
ppc_exec_microseq(int unit, struct ppb_microseq *msq, int *ppbpc)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
struct ppb_microseq *pc;
|
||||
char cc, *p;
|
||||
int i, iter, reg;
|
||||
int error;
|
||||
|
||||
/* static to be reused after few ppc_exec_microseq()/return calls
|
||||
* XXX should be in a context variable shared with ppb level */
|
||||
static int accum;
|
||||
static char *ptr;
|
||||
|
||||
struct ppb_microseq *microseq_stack = 0;
|
||||
struct ppb_microseq *pc_stack = 0;
|
||||
|
||||
/* microsequence registers are equivalent to PC-like port registers */
|
||||
#define r_reg(register,ppc) ((char)inb((ppc)->ppc_base + register))
|
||||
#define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte)
|
||||
|
||||
#define INCR_PC (pc ++) /* increment program counter */
|
||||
#define mi pc /* microinstruction currently executed */
|
||||
|
||||
/* get the state of pc from ppb level of execution */
|
||||
pc = &msq[*ppbpc];
|
||||
|
||||
for (;;) {
|
||||
|
||||
switch (mi->opcode) {
|
||||
case MS_OP_RSET:
|
||||
cc = r_reg(mi->arg[0].i, ppc);
|
||||
cc &= mi->arg[2].c; /* clear mask */
|
||||
cc |= mi->arg[1].c; /* assert mask */
|
||||
w_reg(mi->arg[0].i, ppc, cc);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RASSERT_P:
|
||||
for (i=0; i<mi->arg[0].i; i++)
|
||||
w_reg(mi->arg[1].i, ppc, *ptr++);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RFETCH_P:
|
||||
for (i=0; i<mi->arg[0].i; i++)
|
||||
*ptr++ = r_reg(mi->arg[1].i, ppc) &
|
||||
mi->arg[2].c;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RFETCH:
|
||||
*((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) &
|
||||
mi->arg[1].c;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RASSERT:
|
||||
|
||||
/* let's suppose the next instr. is the same */
|
||||
prefetch:
|
||||
for (;mi->opcode == MS_OP_RASSERT; INCR_PC)
|
||||
w_reg(mi->arg[0].i, ppc, mi->arg[1].c);
|
||||
|
||||
if (mi->opcode == MS_OP_DELAY) {
|
||||
DELAY(mi->arg[0].i);
|
||||
INCR_PC;
|
||||
goto prefetch;
|
||||
}
|
||||
break;
|
||||
|
||||
case MS_OP_DELAY:
|
||||
DELAY(mi->arg[0].i);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_TRIG:
|
||||
reg = mi->arg[0].i;
|
||||
iter = mi->arg[1].i;
|
||||
p = (char *)mi->arg[2].p;
|
||||
|
||||
for (i=0; i<iter; i++) {
|
||||
w_reg(reg, ppc, *p++);
|
||||
DELAY((unsigned char)*p++);
|
||||
}
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_SET:
|
||||
accum = mi->arg[0].i;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_DBRA:
|
||||
if (--accum > 0)
|
||||
pc += mi->arg[0].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_BRSET:
|
||||
cc = r_str(ppc);
|
||||
if ((cc & mi->arg[0].c) == mi->arg[0].c)
|
||||
pc += mi->arg[1].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_BRCLEAR:
|
||||
cc = r_str(ppc);
|
||||
if ((cc & mi->arg[0].c) == 0)
|
||||
pc += mi->arg[1].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_C_CALL:
|
||||
/*
|
||||
* If the C call returns !0 then end the microseq.
|
||||
* The current state of ptr is passed to the C function
|
||||
*/
|
||||
if ((error = mi->arg[0].f(mi->arg[1].p, ptr)))
|
||||
return (error);
|
||||
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_PTR:
|
||||
ptr = (char *)mi->arg[0].p;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_CALL:
|
||||
if (microseq_stack)
|
||||
panic("%s: too much calls", __FUNCTION__);
|
||||
|
||||
if (mi->arg[0].p) {
|
||||
/* store the state of the actual
|
||||
* microsequence
|
||||
*/
|
||||
microseq_stack = msq;
|
||||
pc_stack = pc;
|
||||
|
||||
/* jump to the new microsequence */
|
||||
msq = (struct ppb_microseq *)mi->arg[0].p;
|
||||
pc = msq;
|
||||
} else
|
||||
INCR_PC;
|
||||
|
||||
break;
|
||||
|
||||
case MS_OP_SUBRET:
|
||||
/* retrieve microseq and pc state before the call */
|
||||
msq = microseq_stack;
|
||||
pc = pc_stack;
|
||||
|
||||
/* reset the stack */
|
||||
microseq_stack = 0;
|
||||
|
||||
/* XXX return code */
|
||||
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_PUT:
|
||||
case MS_OP_GET:
|
||||
case MS_OP_RET:
|
||||
/* can't return to ppb level during the execution
|
||||
* of a submicrosequence */
|
||||
if (microseq_stack)
|
||||
panic("%s: can't return to ppb level",
|
||||
__FUNCTION__);
|
||||
|
||||
/* update pc for ppb level of execution */
|
||||
*ppbpc = (int)(pc - msq);
|
||||
|
||||
/* return to ppb level of execution */
|
||||
return (0);
|
||||
|
||||
default:
|
||||
panic("%s: unknown microsequence opcode 0x%x",
|
||||
__FUNCTION__, mi->opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/* unreached */
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure current operating mode
|
||||
*/
|
||||
static int
|
||||
ppc_generic_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, mode);
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -688,16 +1079,14 @@ ppcprobe(struct isa_device *dvp)
|
|||
ppc->ppc_unit = dvp->id_unit;
|
||||
ppc->ppc_type = GENERIC;
|
||||
|
||||
/* PPB_AUTODETECT is default to allow chipset detection even if
|
||||
* mode is forced by dvp->id_flags (see later, ppc_detect() call) */
|
||||
ppc->ppc_mode = PPB_AUTODETECT;
|
||||
ppc->ppc_epp = (dvp->id_flags & 0x8) >> 3;
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Try and detect if interrupts are working.
|
||||
*/
|
||||
if (!(dvp->id_flags & 0x10))
|
||||
if (!(dvp->id_flags & 0x20))
|
||||
ppc->ppc_irq = (dvp->id_irq);
|
||||
|
||||
ppcdata[ppc->ppc_unit] = ppc;
|
||||
|
|
@ -706,7 +1095,7 @@ ppcprobe(struct isa_device *dvp)
|
|||
/*
|
||||
* Try to detect the chipset and its mode.
|
||||
*/
|
||||
if (ppc_detect(ppc, dvp->id_flags & 0x7))
|
||||
if (ppc_detect(ppc, dvp->id_flags & 0xf))
|
||||
goto error;
|
||||
|
||||
end_probe:
|
||||
|
|
@ -722,6 +1111,7 @@ ppcattach(struct isa_device *isdp)
|
|||
{
|
||||
struct ppc_data *ppc = ppcdata[isdp->id_unit];
|
||||
struct ppb_data *ppbus;
|
||||
char * mode;
|
||||
|
||||
/*
|
||||
* Link the Parallel Port Chipset (adapter) to
|
||||
|
|
@ -730,9 +1120,9 @@ ppcattach(struct isa_device *isdp)
|
|||
ppc->ppc_link.adapter_unit = ppc->ppc_unit;
|
||||
ppc->ppc_link.adapter = &ppc_adapter;
|
||||
|
||||
printf("ppc%d: %s chipset in %s mode%s\n", ppc->ppc_unit,
|
||||
ppc_types[ppc->ppc_type], ppc_modes[ppc->ppc_mode],
|
||||
(PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit,
|
||||
ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm],
|
||||
ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
ppc_epp_protocol[ppc->ppc_epp] : "");
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -23,23 +23,25 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppcreg.h,v 1.1 1997/08/14 14:01:36 msmith Exp $
|
||||
* $Id: ppcreg.h,v 1.2 1997/08/16 14:07:26 msmith Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPC_H
|
||||
#define __PPC_H
|
||||
#ifndef __PPCREG_H
|
||||
#define __PPCREG_H
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset type.
|
||||
*/
|
||||
#define SMC_UNKNOWN 0x0
|
||||
#define SMC_LIKE 0x0
|
||||
#define SMC_37C665GT 0x1
|
||||
#define SMC_37C666GT 0x2
|
||||
#define NS_UNKNOWN 0x3
|
||||
#define NS_PC87332 0x4
|
||||
#define NS_PC87306 0x5
|
||||
#define INTEL_820191AA 0x6
|
||||
#define GENERIC 0x7
|
||||
#define NS_PC87332 0x3
|
||||
#define NS_PC87306 0x4
|
||||
#define INTEL_820191AA 0x5 /* XXX not implemented */
|
||||
#define GENERIC 0x6
|
||||
#define WINB_W83877F 0x7
|
||||
#define WINB_W83877AF 0x8
|
||||
#define WINB_UNKNOWN 0x9
|
||||
|
||||
/*
|
||||
* Generic structure to hold parallel port chipset info.
|
||||
|
|
@ -49,21 +51,19 @@ struct ppc_data {
|
|||
int ppc_unit;
|
||||
int ppc_type;
|
||||
|
||||
int ppc_mode; /* chipset current mode */
|
||||
int ppc_avm; /* chipset available modes */
|
||||
|
||||
#define ppc_base ppc_link.base
|
||||
#define ppc_mode ppc_link.mode
|
||||
#define ppc_epp ppc_link.epp_protocol
|
||||
#define ppc_irq ppc_link.id_irq
|
||||
#define ppc_subm ppc_link.submicroseq
|
||||
|
||||
unsigned char ppc_flags;
|
||||
|
||||
struct ppb_link ppc_link;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset errors. XXX
|
||||
*/
|
||||
#define PPC_ENOPORT 9
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset registers.
|
||||
*/
|
||||
|
|
@ -74,12 +74,12 @@ struct ppc_data {
|
|||
#define PPC_ECP_FIFO 0x400 /* ECP fifo register */
|
||||
#define PPC_ECP_ECR 0x402 /* ECP extended control register */
|
||||
|
||||
#define r_dtr(ppc) inb((ppc)->ppc_base + PPC_SPP_DTR)
|
||||
#define r_str(ppc) inb((ppc)->ppc_base + PPC_SPP_STR)
|
||||
#define r_ctr(ppc) inb((ppc)->ppc_base + PPC_SPP_CTR)
|
||||
#define r_epp(ppc) inb((ppc)->ppc_base + PPC_EPP_DATA)
|
||||
#define r_ecr(ppc) inb((ppc)->ppc_base + PPC_ECP_ECR)
|
||||
#define r_fifo(ppc) inb((ppc)->ppc_base + PPC_ECP_FIFO)
|
||||
#define r_dtr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_DTR))
|
||||
#define r_str(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_STR))
|
||||
#define r_ctr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_CTR))
|
||||
#define r_epp(ppc) ((char)inb((ppc)->ppc_base + PPC_EPP_DATA))
|
||||
#define r_ecr(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_ECR))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_FIFO))
|
||||
|
||||
#define w_dtr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_DTR, byte)
|
||||
#define w_str(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_STR, byte)
|
||||
|
|
@ -111,7 +111,7 @@ struct ppc_data {
|
|||
#define PC873_SID 0x08
|
||||
|
||||
/*
|
||||
* Register defines for the SMC FDC37C66xGT parts.
|
||||
* Register defines for the SMC FDC37C66xGT parts
|
||||
*/
|
||||
|
||||
/* Init codes */
|
||||
|
|
@ -124,9 +124,9 @@ struct ppc_data {
|
|||
|
||||
/* Bits */
|
||||
#define SMC_CR1_ADDR 0x3 /* bit 0 and 1 */
|
||||
#define SMC_CR1_MODE 0x8 /* bit 3 */
|
||||
#define SMC_CR1_MODE (1<<3) /* bit 3 */
|
||||
#define SMC_CR4_EMODE 0x3 /* bits 0 and 1 */
|
||||
#define SMC_CR4_EPPTYPE 0x40 /* bit 6 */
|
||||
#define SMC_CR4_EPPTYPE (1<<6) /* bit 6 */
|
||||
|
||||
/* Extended modes */
|
||||
#define SMC_SPP 0x0 /* SPP */
|
||||
|
|
@ -134,5 +134,34 @@ struct ppc_data {
|
|||
#define SMC_ECP 0x2 /* ECP */
|
||||
#define SMC_ECPEPP 0x3 /* ECP and EPP */
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Register defines for the Winbond W83877F parts
|
||||
*/
|
||||
|
||||
#define WINB_W83877F_ID 0xa
|
||||
#define WINB_W83877AF_ID 0xb
|
||||
|
||||
/* Configuration bits */
|
||||
#define WINB_HEFERE (1<<5) /* CROC bit 5 */
|
||||
#define WINB_HEFRAS (1<<0) /* CR16 bit 0 */
|
||||
|
||||
#define WINB_PNPCVS (1<<2) /* CR16 bit 2 */
|
||||
#define WINB_CHIPID 0xf /* CR9 bits 0-3 */
|
||||
|
||||
#define WINB_PRTMODS0 (1<<2) /* CR0 bit 2 */
|
||||
#define WINB_PRTMODS1 (1<<3) /* CR0 bit 3 */
|
||||
#define WINB_PRTMODS2 (1<<7) /* CR9 bit 7 */
|
||||
|
||||
/* W83877F modes: CR9/bit7 | CR0/bit3 | CR0/bit2 */
|
||||
#define WINB_W83757 0x0
|
||||
#define WINB_EXTFDC 0x4
|
||||
#define WINB_EXTADP 0x8
|
||||
#define WINB_EXT2FDD 0xc
|
||||
#define WINB_JOYSTICK 0x80
|
||||
|
||||
#define WINB_PARALLEL 0x80
|
||||
#define WINB_EPP_SPP 0x4
|
||||
#define WINB_ECP 0x8
|
||||
#define WINB_ECP_EPP 0xc
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.446 1998/07/11 04:46:27 julian Exp $
|
||||
# $Id: LINT,v 1.447 1998/07/20 20:00:30 msmith Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
|
|
@ -1440,6 +1440,7 @@ options POWERFAIL_NMI # make it beep instead of panicing
|
|||
# Requires SCSI disk support ('scbus' and 'sd'), best
|
||||
# performance is achieved with ports in EPP 1.9 mode.
|
||||
# nlpt Parallel Printer
|
||||
# plip Parallel network interface
|
||||
# ppi General-purpose I/O ("Geek Port")
|
||||
#
|
||||
# Supported interfaces:
|
||||
|
|
@ -1448,6 +1449,7 @@ options POWERFAIL_NMI # make it beep instead of panicing
|
|||
controller ppbus0
|
||||
controller vpo0 at ppbus?
|
||||
device nlpt0 at ppbus?
|
||||
device plip0 at ppbus?
|
||||
device ppi0 at ppbus?
|
||||
device pps0 at ppbus?
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.446 1998/07/11 04:46:27 julian Exp $
|
||||
# $Id: LINT,v 1.447 1998/07/20 20:00:30 msmith Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
|
|
@ -1440,6 +1440,7 @@ options POWERFAIL_NMI # make it beep instead of panicing
|
|||
# Requires SCSI disk support ('scbus' and 'sd'), best
|
||||
# performance is achieved with ports in EPP 1.9 mode.
|
||||
# nlpt Parallel Printer
|
||||
# plip Parallel network interface
|
||||
# ppi General-purpose I/O ("Geek Port")
|
||||
#
|
||||
# Supported interfaces:
|
||||
|
|
@ -1448,6 +1449,7 @@ options POWERFAIL_NMI # make it beep instead of panicing
|
|||
controller ppbus0
|
||||
controller vpo0 at ppbus?
|
||||
device nlpt0 at ppbus?
|
||||
device plip0 at ppbus?
|
||||
device ppi0 at ppbus?
|
||||
device pps0 at ppbus?
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Nicolas Souchu
|
||||
* Copyright (c) 1997, 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppc.c,v 1.2 1997/09/01 02:08:41 bde Exp $
|
||||
* $Id: ppc.c,v 1.3 1998/04/17 22:36:37 des Exp $
|
||||
*
|
||||
*/
|
||||
#include "ppc.h"
|
||||
|
|
@ -44,6 +44,8 @@
|
|||
#include <i386/isa/isa_device.h>
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
|
||||
#include <i386/isa/ppcreg.h>
|
||||
|
||||
static int ppcprobe(struct isa_device *);
|
||||
|
|
@ -57,14 +59,26 @@ static struct ppc_data *ppcdata[NPPC];
|
|||
static int nppc = 0;
|
||||
|
||||
static char *ppc_types[] = {
|
||||
"SMC", "SMC FDC37C665GT", "SMC FDC37C666GT",
|
||||
"NatSemi", "PC87332", "PC87306",
|
||||
"Intel 82091AA", "Generic", 0
|
||||
"SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306",
|
||||
"82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0
|
||||
};
|
||||
|
||||
/* list of available modes */
|
||||
static char *ppc_avms[] = {
|
||||
"COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only",
|
||||
"EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only",
|
||||
"ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP",
|
||||
"ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0
|
||||
};
|
||||
|
||||
/* list of current executing modes
|
||||
* Note that few modes do not actually exist.
|
||||
*/
|
||||
static char *ppc_modes[] = {
|
||||
"AUTODETECT", "NIBBLE", "PS/2", "EPP", "ECP+EPP", "ECP+PS/2", "ECP",
|
||||
"UNKNOWN", 0
|
||||
"COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP",
|
||||
"EPP", "EPP", "EPP", "ECP",
|
||||
"ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP",
|
||||
"ECP+EPP", "ECP+EPP", "ECP+EPP", 0
|
||||
};
|
||||
|
||||
static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 };
|
||||
|
|
@ -110,12 +124,19 @@ static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); }
|
|||
static void ppc_reset_epp_timeout(int);
|
||||
static void ppc_ecp_sync(int);
|
||||
|
||||
static int ppc_exec_microseq(int, struct ppb_microseq *, int *);
|
||||
static int ppc_generic_setmode(int, int);
|
||||
|
||||
static struct ppb_adapter ppc_adapter = {
|
||||
|
||||
0, /* no intr handler, filled by chipset dependent code */
|
||||
|
||||
ppc_reset_epp_timeout, ppc_ecp_sync,
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_generic_setmode,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
|
||||
|
|
@ -143,8 +164,8 @@ ppc_ecp_sync(int unit) {
|
|||
DELAY(100);
|
||||
}
|
||||
|
||||
printf("ppc: ECP sync failed as data still " \
|
||||
"present in FIFO.\n");
|
||||
printf("ppc%d: ECP sync failed as data still " \
|
||||
"present in FIFO.\n", unit);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -158,6 +179,35 @@ ppcintr(int unit)
|
|||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ppc_ecp_config(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (chipset_mode & PPB_EPP)
|
||||
/* select EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
else if (chipset_mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
else
|
||||
/* keep ECP mode alone, default for NIBBLE */
|
||||
w_ecr(ppc, 0x70);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_detect_port(struct ppc_data *ppc)
|
||||
{
|
||||
|
||||
w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */
|
||||
w_dtr(ppc, 0xaa);
|
||||
if (r_dtr(ppc) != (char) 0xaa)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_pc873xx_detect
|
||||
*
|
||||
|
|
@ -170,11 +220,11 @@ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0};
|
|||
static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0};
|
||||
|
||||
static int
|
||||
ppc_pc873xx_detect(struct ppc_data *ppc)
|
||||
ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */
|
||||
{
|
||||
static int index = 0;
|
||||
int base, idport;
|
||||
int val, mode;
|
||||
int val;
|
||||
|
||||
while ((idport = pc873xx_basetab[index++])) {
|
||||
|
||||
|
|
@ -235,7 +285,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
printf("PC873xx locked\n");
|
||||
|
||||
/* work out what mode we're in */
|
||||
mode = PPB_NIBBLE; /* worst case */
|
||||
ppc->ppc_avm |= PPB_NIBBLE; /* worst case */
|
||||
|
||||
outb(idport, PC873_PCR);
|
||||
val = inb(idport + 1);
|
||||
|
|
@ -243,10 +293,10 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport, PC873_PTR);
|
||||
val = inb(idport + 1);
|
||||
if (!(val & PC873_EPPRDIR)) {
|
||||
mode = PPB_EPP; /* As we would have done it anwyay */
|
||||
ppc->ppc_avm |= PPB_EPP; /* As we would have done it anwyay */
|
||||
}
|
||||
} else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) {
|
||||
mode = PPB_PS2; /* tolerable alternative */
|
||||
ppc->ppc_avm |= PPB_PS2; /* tolerable alternative */
|
||||
}
|
||||
} else {
|
||||
if (bootverbose)
|
||||
|
|
@ -299,7 +349,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport + 1, val);
|
||||
|
||||
/* we are an EPP-32 port */
|
||||
mode = PPB_EPP;
|
||||
ppc->ppc_avm |= PPB_EPP;
|
||||
} else {
|
||||
if (bootverbose)
|
||||
printf("ECP\n");
|
||||
|
|
@ -309,44 +359,21 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK);
|
||||
|
||||
/* we look like a PS/2 port */
|
||||
mode = PPB_PS2;
|
||||
ppc->ppc_avm |= PPB_PS2;
|
||||
}
|
||||
}
|
||||
return(mode);
|
||||
|
||||
return(chipset_mode);
|
||||
}
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_detect_ps2(struct ppc_data *ppc)
|
||||
ppc_check_epp_timeout(struct ppc_data *ppc)
|
||||
{
|
||||
char save_control, r;
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
|
||||
save_control = r_ctr(ppc);
|
||||
|
||||
/* Try PS/2 mode */
|
||||
w_ctr(ppc, 0xec);
|
||||
w_dtr(ppc, 0x55);
|
||||
|
||||
/* needed if in ECP mode */
|
||||
if (ppc->ppc_mode == PPB_ECP)
|
||||
w_ctr(ppc, PCD | 0xec);
|
||||
r = r_dtr(ppc);
|
||||
|
||||
if (r != (char) 0xff) {
|
||||
if (r != (char) 0x55)
|
||||
return 0;
|
||||
|
||||
w_dtr(ppc, 0xaa);
|
||||
r = r_dtr(ppc);
|
||||
if (r != (char) 0xaa)
|
||||
return 0;
|
||||
|
||||
return (PPB_NIBBLE);
|
||||
} else
|
||||
w_ctr(ppc, save_control);
|
||||
|
||||
return (PPB_PS2);
|
||||
return (!(r_str(ppc) & TIMEOUT));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -355,11 +382,10 @@ ppc_detect_ps2(struct ppc_data *ppc)
|
|||
* SMC FDC37C66xGT configuration.
|
||||
*/
|
||||
static int
|
||||
ppc_smc37c66xgt_detect(struct ppc_data *ppc, int mode)
|
||||
ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
int s, i;
|
||||
char r;
|
||||
int retry = 0; /* boolean */
|
||||
int type = -1;
|
||||
int csr = SMC66x_CSR; /* initial value is 0x3F0 */
|
||||
|
||||
|
|
@ -404,7 +430,7 @@ config:
|
|||
* If chipset not found, do not continue.
|
||||
*/
|
||||
if (type == -1)
|
||||
return (0);
|
||||
return (-1);
|
||||
|
||||
/* select CR1 */
|
||||
outb(csr, 0x1);
|
||||
|
|
@ -412,65 +438,72 @@ config:
|
|||
/* read the port's address: bits 0 and 1 of CR1 */
|
||||
r = inb(cio) & SMC_CR1_ADDR;
|
||||
if (port_address[r] != ppc->ppc_base)
|
||||
return (0);
|
||||
return (-1);
|
||||
|
||||
ppc->ppc_type = type;
|
||||
|
||||
/*
|
||||
* CR1 and CR4 registers bits 3 and 0/1 for mode configuration
|
||||
* If SPP mode is detected, try to set ECP+EPP mode end retry
|
||||
* detection to verify.
|
||||
* If SPP mode is detected, try to set ECP+EPP mode
|
||||
*/
|
||||
|
||||
retry:
|
||||
/* select CR1 register */
|
||||
if (bootverbose) {
|
||||
outb(csr, 0x1);
|
||||
printf("SMC registers CR1=0x%x", ppc->ppc_unit,
|
||||
inb(cio) & 0xff);
|
||||
|
||||
outb(csr, 0x4);
|
||||
printf(" CR4=0x%x", inb(cio) & 0xff);
|
||||
}
|
||||
|
||||
/* select CR1 */
|
||||
outb(csr, 0x1);
|
||||
|
||||
if (!mode) {
|
||||
if (!chipset_mode) {
|
||||
/* autodetect mode */
|
||||
|
||||
/* 666GT chipset is hardwired to an extended mode */
|
||||
if (type == SMC_37C666GT)
|
||||
mode = PPB_ECP_EPP;
|
||||
/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
|
||||
if (type == SMC_37C666GT) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
|
||||
else if ((inb(cio) & SMC_CR1_MODE) == 0) {
|
||||
} else
|
||||
if ((inb(cio) & SMC_CR1_MODE) == 0) {
|
||||
/* already in extended parallel port mode, read CR4 */
|
||||
outb(csr, 0x4);
|
||||
r = (inb(cio) & SMC_CR4_EMODE);
|
||||
|
||||
switch (r) {
|
||||
case SMC_SPP:
|
||||
/* let's detect NIBBLE or PS/2 later */
|
||||
ppc->ppc_avm |= PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_EPPSPP:
|
||||
mode = PPB_EPP;
|
||||
ppc->ppc_avm |= PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_ECP:
|
||||
/*
|
||||
* Yet, don't know what to do with it! XXX
|
||||
* So, consider ECP mode as PS/2.
|
||||
* (see configuration later).
|
||||
*/
|
||||
mode = PPB_ECP;
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_ECPEPP:
|
||||
mode = PPB_ECP_EPP;
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* not an extended port mode */
|
||||
ppc->ppc_avm |= PPB_SPP;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* mode forced */
|
||||
|
||||
/* 666GT chipset is hardwired to an extended mode */
|
||||
/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
|
||||
if (type == SMC_37C666GT)
|
||||
goto end_detect;
|
||||
|
||||
r = inb(cio);
|
||||
if (mode == PPB_NIBBLE || mode == PPB_PS2) {
|
||||
/* do not use ECP when the mode is forced to SPP */
|
||||
if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) {
|
||||
/* do not use ECP when the mode is not forced to */
|
||||
outb(cio, r | SMC_CR1_MODE);
|
||||
} else {
|
||||
/* an extended mode is selected */
|
||||
|
|
@ -480,30 +513,26 @@ retry:
|
|||
outb(csr, 0x4);
|
||||
r = inb(cio) & ~SMC_CR4_EMODE;
|
||||
|
||||
switch (mode) {
|
||||
case PPB_EPP:
|
||||
if (chipset_mode & PPB_ECP) {
|
||||
if (chipset_mode & PPB_EPP) {
|
||||
outb(cio, r | SMC_ECPEPP);
|
||||
} else {
|
||||
outb(cio, r | SMC_ECP);
|
||||
}
|
||||
} else {
|
||||
/* PPB_EPP is set */
|
||||
outb(cio, r | SMC_EPPSPP);
|
||||
break;
|
||||
|
||||
case PPB_ECP:
|
||||
case PPB_ECP_PS2:
|
||||
outb(cio, r | SMC_ECP);
|
||||
break;
|
||||
|
||||
case PPB_ECP_EPP:
|
||||
outb(cio, r | SMC_ECPEPP);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("ppc: unknown mode (%d)\n",
|
||||
mode);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
end_detect:
|
||||
if (PPB_IS_EPP(mode)) {
|
||||
|
||||
if (bootverbose)
|
||||
printf ("\n");
|
||||
|
||||
if (chipset_mode & PPB_EPP) {
|
||||
/* select CR4 */
|
||||
outb(csr, 0x4);
|
||||
r = inb(cio);
|
||||
|
|
@ -511,11 +540,9 @@ end_detect:
|
|||
/*
|
||||
* Set the EPP protocol...
|
||||
* Low=EPP 1.9 (1284 standard) and High=EPP 1.7
|
||||
* ...then check the result.
|
||||
*/
|
||||
if (ppc->ppc_epp == EPP_1_9)
|
||||
outb(cio, (r & ~SMC_CR4_EPPTYPE));
|
||||
|
||||
else
|
||||
outb(cio, (r | SMC_CR4_EPPTYPE));
|
||||
}
|
||||
|
|
@ -523,86 +550,214 @@ end_detect:
|
|||
/* end config mode */
|
||||
outb(csr, 0xaa);
|
||||
|
||||
/*
|
||||
* Write 100 to the mode bits and disable DMA, enable intr.
|
||||
*/
|
||||
if (mode == PPB_ECP_EPP)
|
||||
w_ecr(ppc, 0x80);
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
/*
|
||||
* Write 001 to the mode bits and disable DMA, enable intr.
|
||||
*/
|
||||
if (mode == PPB_ECP)
|
||||
w_ecr(ppc, 0x20);
|
||||
|
||||
if (PPB_IS_EPP(mode)) {
|
||||
/*
|
||||
* Try to reset EPP timeout bit.
|
||||
* If it fails, try PS/2 and NIBBLE modes.
|
||||
*/
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT))
|
||||
return (mode);
|
||||
} else {
|
||||
if (mode)
|
||||
return (mode);
|
||||
}
|
||||
|
||||
/* detect PS/2 or NIBBLE mode */
|
||||
return (ppc_detect_ps2(ppc));
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Winbond W83877F stuff
|
||||
*
|
||||
* EFER: extended function enable register
|
||||
* EFIR: extended function index register
|
||||
* EFDR: extended function data register
|
||||
*/
|
||||
#define efir ((efer == 0x250) ? 0x251 : 0x3f0)
|
||||
#define efdr ((efer == 0x250) ? 0x252 : 0x3f1)
|
||||
|
||||
static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 };
|
||||
static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 };
|
||||
static int w83877f_keyiter[] = { 1, 2, 2, 1 };
|
||||
static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 };
|
||||
|
||||
static int
|
||||
ppc_check_ecpepp_timeout(struct ppc_data *ppc)
|
||||
ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
char r;
|
||||
int i, j, efer, base;
|
||||
unsigned char r, hefere, hefras;
|
||||
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
for (i = 0; i < 4; i ++) {
|
||||
/* first try to enable configuration registers */
|
||||
efer = w83877f_efers[i];
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT)) {
|
||||
return (PPB_ECP_EPP);
|
||||
/* write the key to the EFER */
|
||||
for (j = 0; j < w83877f_keyiter[i]; j ++)
|
||||
outb (efer, w83877f_keys[i]);
|
||||
|
||||
/* then check HEFERE and HEFRAS bits */
|
||||
outb (efir, 0x0c);
|
||||
hefere = inb(efdr) & WINB_HEFERE;
|
||||
|
||||
outb (efir, 0x16);
|
||||
hefras = inb(efdr) & WINB_HEFRAS;
|
||||
|
||||
/*
|
||||
* HEFRAS HEFERE
|
||||
* 0 1 write 89h to 250h (power-on default)
|
||||
* 1 0 write 86h twice to 3f0h
|
||||
* 1 1 write 87h twice to 3f0h
|
||||
* 0 0 write 88h to 250h
|
||||
*/
|
||||
if ((hefere | hefras) == w83877f_hefs[i])
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* If EPP timeout bit is not reset, DON'T use EPP */
|
||||
w_ecr(ppc, 0x20);
|
||||
return (-1); /* failed */
|
||||
|
||||
return (PPB_ECP_PS2);
|
||||
found:
|
||||
/* check base port address - read from CR23 */
|
||||
outb(efir, 0x23);
|
||||
if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */
|
||||
return (-1);
|
||||
|
||||
/* read CHIP ID from CR9/bits0-3 */
|
||||
outb(efir, 0x9);
|
||||
|
||||
switch (inb(efdr) & WINB_CHIPID) {
|
||||
case WINB_W83877F_ID:
|
||||
ppc->ppc_type = WINB_W83877F;
|
||||
break;
|
||||
|
||||
case WINB_W83877AF_ID:
|
||||
ppc->ppc_type = WINB_W83877AF;
|
||||
break;
|
||||
|
||||
default:
|
||||
ppc->ppc_type = WINB_UNKNOWN;
|
||||
}
|
||||
|
||||
if (bootverbose) {
|
||||
/* dump of registers */
|
||||
printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]);
|
||||
for (i = 0; i <= 0xd; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
for (i = 0x10; i <= 0x17; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
outb(efir, 0x1e);
|
||||
printf("0x%x ", inb(efdr));
|
||||
for (i = 0x20; i <= 0x29; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (!chipset_mode) {
|
||||
/* autodetect mode */
|
||||
|
||||
/* select CR0 */
|
||||
outb(efir, 0x0);
|
||||
r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1);
|
||||
|
||||
/* select CR9 */
|
||||
outb(efir, 0x9);
|
||||
r |= (inb(efdr) & WINB_PRTMODS2);
|
||||
|
||||
switch (r) {
|
||||
case WINB_W83757:
|
||||
if (bootverbose)
|
||||
printf("ppc%d: W83757 compatible mode\n",
|
||||
ppc->ppc_unit);
|
||||
return (-1); /* generic or SMC-like */
|
||||
|
||||
case WINB_EXTFDC:
|
||||
case WINB_EXTADP:
|
||||
case WINB_EXT2FDD:
|
||||
case WINB_JOYSTICK:
|
||||
if (bootverbose)
|
||||
printf("ppc%d: not in parallel port mode\n",
|
||||
ppc->ppc_unit);
|
||||
return (-1);
|
||||
|
||||
case (WINB_PARALLEL | WINB_EPP_SPP):
|
||||
ppc->ppc_avm |= PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case (WINB_PARALLEL | WINB_ECP):
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case (WINB_PARALLEL | WINB_ECP_EPP):
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
default:
|
||||
printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* mode forced */
|
||||
|
||||
/* select CR9 and set PRTMODS2 bit */
|
||||
outb(efir, 0x9);
|
||||
outb(efdr, inb(efdr) & ~WINB_PRTMODS2);
|
||||
|
||||
/* select CR0 and reset PRTMODSx bits */
|
||||
outb(efir, 0x0);
|
||||
outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1));
|
||||
|
||||
if (chipset_mode & PPB_ECP) {
|
||||
if (chipset_mode & PPB_EPP)
|
||||
outb(efdr, inb(efdr) | WINB_ECP_EPP);
|
||||
else
|
||||
outb(efdr, inb(efdr) | WINB_ECP);
|
||||
} else {
|
||||
/* select EPP_SPP otherwise */
|
||||
outb(efdr, inb(efdr) | WINB_EPP_SPP);
|
||||
}
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
/* exit configuration mode */
|
||||
outb(efer, 0xaa);
|
||||
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_generic_detect
|
||||
*/
|
||||
static int
|
||||
ppc_generic_detect(struct ppc_data *ppc, int mode)
|
||||
ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
char save_control, r;
|
||||
char save_control;
|
||||
|
||||
/* don't know what to do here */
|
||||
if (mode)
|
||||
return (mode);
|
||||
if (!chipset_mode) {
|
||||
/* first, check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
if ((r_ecr(ppc) & 0xe0) == 0x20) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
|
||||
/* try to reset EPP timeout bit */
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
/* search for SMC style ECP+EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
}
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT)) {
|
||||
return (PPB_EPP);
|
||||
}
|
||||
/* try to reset EPP timeout bit */
|
||||
if (ppc_check_epp_timeout(ppc)) {
|
||||
ppc->ppc_avm |= PPB_EPP;
|
||||
|
||||
/* Now check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
r = r_ecr(ppc);
|
||||
if ((r & 0xe0) == 0x20) {
|
||||
/* Search for SMC style EPP+ECP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
/* SMC like chipset found */
|
||||
ppc->ppc_type = SMC_LIKE;
|
||||
}
|
||||
|
||||
return (ppc_check_ecpepp_timeout(ppc));
|
||||
}
|
||||
/* XXX try to detect NIBBLE mode */
|
||||
ppc->ppc_avm |= PPB_NIBBLE;
|
||||
|
||||
return (ppc_detect_ps2(ppc));
|
||||
} else
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -611,22 +766,258 @@ ppc_generic_detect(struct ppc_data *ppc, int mode)
|
|||
* mode is the mode suggested at boot
|
||||
*/
|
||||
static int
|
||||
ppc_detect(struct ppc_data *ppc, int mode) {
|
||||
ppc_detect(struct ppc_data *ppc, int chipset_mode) {
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_pc873xx_detect(ppc)))
|
||||
goto end_detect;
|
||||
int i, mode;
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode =
|
||||
ppc_smc37c66xgt_detect(ppc, mode)))
|
||||
goto end_detect;
|
||||
/* list of supported chipsets */
|
||||
int (*chipset_detect[])(struct ppc_data *, int) = {
|
||||
ppc_pc873xx_detect,
|
||||
ppc_smc37c66xgt_detect,
|
||||
ppc_w83877f_detect,
|
||||
ppc_generic_detect,
|
||||
NULL
|
||||
};
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_generic_detect(ppc, mode)))
|
||||
goto end_detect;
|
||||
/* if can't find the port and mode not forced return error */
|
||||
if (!ppc_detect_port(ppc) && chipset_mode == 0)
|
||||
return (EIO); /* failed, port not present */
|
||||
|
||||
printf("ppc: port not present at 0x%x.\n", ppc->ppc_base);
|
||||
return (PPC_ENOPORT);
|
||||
/* assume centronics compatible mode is supported */
|
||||
ppc->ppc_avm = PPB_COMPATIBLE;
|
||||
|
||||
end_detect:
|
||||
/* we have to differenciate available chipset modes,
|
||||
* chipset running modes and IEEE-1284 operating modes
|
||||
*
|
||||
* after detection, the port must support running in compatible mode
|
||||
*/
|
||||
for (i=0; chipset_detect[i] != NULL; i++) {
|
||||
if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) {
|
||||
ppc->ppc_mode = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_exec_microseq()
|
||||
*
|
||||
* Execute a microsequence.
|
||||
* Microsequence mechanism is supposed to handle fast I/O operations.
|
||||
*/
|
||||
static int
|
||||
ppc_exec_microseq(int unit, struct ppb_microseq *msq, int *ppbpc)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
struct ppb_microseq *pc;
|
||||
char cc, *p;
|
||||
int i, iter, reg;
|
||||
int error;
|
||||
|
||||
/* static to be reused after few ppc_exec_microseq()/return calls
|
||||
* XXX should be in a context variable shared with ppb level */
|
||||
static int accum;
|
||||
static char *ptr;
|
||||
|
||||
struct ppb_microseq *microseq_stack = 0;
|
||||
struct ppb_microseq *pc_stack = 0;
|
||||
|
||||
/* microsequence registers are equivalent to PC-like port registers */
|
||||
#define r_reg(register,ppc) ((char)inb((ppc)->ppc_base + register))
|
||||
#define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte)
|
||||
|
||||
#define INCR_PC (pc ++) /* increment program counter */
|
||||
#define mi pc /* microinstruction currently executed */
|
||||
|
||||
/* get the state of pc from ppb level of execution */
|
||||
pc = &msq[*ppbpc];
|
||||
|
||||
for (;;) {
|
||||
|
||||
switch (mi->opcode) {
|
||||
case MS_OP_RSET:
|
||||
cc = r_reg(mi->arg[0].i, ppc);
|
||||
cc &= mi->arg[2].c; /* clear mask */
|
||||
cc |= mi->arg[1].c; /* assert mask */
|
||||
w_reg(mi->arg[0].i, ppc, cc);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RASSERT_P:
|
||||
for (i=0; i<mi->arg[0].i; i++)
|
||||
w_reg(mi->arg[1].i, ppc, *ptr++);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RFETCH_P:
|
||||
for (i=0; i<mi->arg[0].i; i++)
|
||||
*ptr++ = r_reg(mi->arg[1].i, ppc) &
|
||||
mi->arg[2].c;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RFETCH:
|
||||
*((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) &
|
||||
mi->arg[1].c;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RASSERT:
|
||||
|
||||
/* let's suppose the next instr. is the same */
|
||||
prefetch:
|
||||
for (;mi->opcode == MS_OP_RASSERT; INCR_PC)
|
||||
w_reg(mi->arg[0].i, ppc, mi->arg[1].c);
|
||||
|
||||
if (mi->opcode == MS_OP_DELAY) {
|
||||
DELAY(mi->arg[0].i);
|
||||
INCR_PC;
|
||||
goto prefetch;
|
||||
}
|
||||
break;
|
||||
|
||||
case MS_OP_DELAY:
|
||||
DELAY(mi->arg[0].i);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_TRIG:
|
||||
reg = mi->arg[0].i;
|
||||
iter = mi->arg[1].i;
|
||||
p = (char *)mi->arg[2].p;
|
||||
|
||||
for (i=0; i<iter; i++) {
|
||||
w_reg(reg, ppc, *p++);
|
||||
DELAY((unsigned char)*p++);
|
||||
}
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_SET:
|
||||
accum = mi->arg[0].i;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_DBRA:
|
||||
if (--accum > 0)
|
||||
pc += mi->arg[0].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_BRSET:
|
||||
cc = r_str(ppc);
|
||||
if ((cc & mi->arg[0].c) == mi->arg[0].c)
|
||||
pc += mi->arg[1].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_BRCLEAR:
|
||||
cc = r_str(ppc);
|
||||
if ((cc & mi->arg[0].c) == 0)
|
||||
pc += mi->arg[1].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_C_CALL:
|
||||
/*
|
||||
* If the C call returns !0 then end the microseq.
|
||||
* The current state of ptr is passed to the C function
|
||||
*/
|
||||
if ((error = mi->arg[0].f(mi->arg[1].p, ptr)))
|
||||
return (error);
|
||||
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_PTR:
|
||||
ptr = (char *)mi->arg[0].p;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_CALL:
|
||||
if (microseq_stack)
|
||||
panic("%s: too much calls", __FUNCTION__);
|
||||
|
||||
if (mi->arg[0].p) {
|
||||
/* store the state of the actual
|
||||
* microsequence
|
||||
*/
|
||||
microseq_stack = msq;
|
||||
pc_stack = pc;
|
||||
|
||||
/* jump to the new microsequence */
|
||||
msq = (struct ppb_microseq *)mi->arg[0].p;
|
||||
pc = msq;
|
||||
} else
|
||||
INCR_PC;
|
||||
|
||||
break;
|
||||
|
||||
case MS_OP_SUBRET:
|
||||
/* retrieve microseq and pc state before the call */
|
||||
msq = microseq_stack;
|
||||
pc = pc_stack;
|
||||
|
||||
/* reset the stack */
|
||||
microseq_stack = 0;
|
||||
|
||||
/* XXX return code */
|
||||
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_PUT:
|
||||
case MS_OP_GET:
|
||||
case MS_OP_RET:
|
||||
/* can't return to ppb level during the execution
|
||||
* of a submicrosequence */
|
||||
if (microseq_stack)
|
||||
panic("%s: can't return to ppb level",
|
||||
__FUNCTION__);
|
||||
|
||||
/* update pc for ppb level of execution */
|
||||
*ppbpc = (int)(pc - msq);
|
||||
|
||||
/* return to ppb level of execution */
|
||||
return (0);
|
||||
|
||||
default:
|
||||
panic("%s: unknown microsequence opcode 0x%x",
|
||||
__FUNCTION__, mi->opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/* unreached */
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure current operating mode
|
||||
*/
|
||||
static int
|
||||
ppc_generic_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, mode);
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -688,16 +1079,14 @@ ppcprobe(struct isa_device *dvp)
|
|||
ppc->ppc_unit = dvp->id_unit;
|
||||
ppc->ppc_type = GENERIC;
|
||||
|
||||
/* PPB_AUTODETECT is default to allow chipset detection even if
|
||||
* mode is forced by dvp->id_flags (see later, ppc_detect() call) */
|
||||
ppc->ppc_mode = PPB_AUTODETECT;
|
||||
ppc->ppc_epp = (dvp->id_flags & 0x8) >> 3;
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Try and detect if interrupts are working.
|
||||
*/
|
||||
if (!(dvp->id_flags & 0x10))
|
||||
if (!(dvp->id_flags & 0x20))
|
||||
ppc->ppc_irq = (dvp->id_irq);
|
||||
|
||||
ppcdata[ppc->ppc_unit] = ppc;
|
||||
|
|
@ -706,7 +1095,7 @@ ppcprobe(struct isa_device *dvp)
|
|||
/*
|
||||
* Try to detect the chipset and its mode.
|
||||
*/
|
||||
if (ppc_detect(ppc, dvp->id_flags & 0x7))
|
||||
if (ppc_detect(ppc, dvp->id_flags & 0xf))
|
||||
goto error;
|
||||
|
||||
end_probe:
|
||||
|
|
@ -722,6 +1111,7 @@ ppcattach(struct isa_device *isdp)
|
|||
{
|
||||
struct ppc_data *ppc = ppcdata[isdp->id_unit];
|
||||
struct ppb_data *ppbus;
|
||||
char * mode;
|
||||
|
||||
/*
|
||||
* Link the Parallel Port Chipset (adapter) to
|
||||
|
|
@ -730,9 +1120,9 @@ ppcattach(struct isa_device *isdp)
|
|||
ppc->ppc_link.adapter_unit = ppc->ppc_unit;
|
||||
ppc->ppc_link.adapter = &ppc_adapter;
|
||||
|
||||
printf("ppc%d: %s chipset in %s mode%s\n", ppc->ppc_unit,
|
||||
ppc_types[ppc->ppc_type], ppc_modes[ppc->ppc_mode],
|
||||
(PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit,
|
||||
ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm],
|
||||
ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
ppc_epp_protocol[ppc->ppc_epp] : "");
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -23,23 +23,25 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppcreg.h,v 1.1 1997/08/14 14:01:36 msmith Exp $
|
||||
* $Id: ppcreg.h,v 1.2 1997/08/16 14:07:26 msmith Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPC_H
|
||||
#define __PPC_H
|
||||
#ifndef __PPCREG_H
|
||||
#define __PPCREG_H
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset type.
|
||||
*/
|
||||
#define SMC_UNKNOWN 0x0
|
||||
#define SMC_LIKE 0x0
|
||||
#define SMC_37C665GT 0x1
|
||||
#define SMC_37C666GT 0x2
|
||||
#define NS_UNKNOWN 0x3
|
||||
#define NS_PC87332 0x4
|
||||
#define NS_PC87306 0x5
|
||||
#define INTEL_820191AA 0x6
|
||||
#define GENERIC 0x7
|
||||
#define NS_PC87332 0x3
|
||||
#define NS_PC87306 0x4
|
||||
#define INTEL_820191AA 0x5 /* XXX not implemented */
|
||||
#define GENERIC 0x6
|
||||
#define WINB_W83877F 0x7
|
||||
#define WINB_W83877AF 0x8
|
||||
#define WINB_UNKNOWN 0x9
|
||||
|
||||
/*
|
||||
* Generic structure to hold parallel port chipset info.
|
||||
|
|
@ -49,21 +51,19 @@ struct ppc_data {
|
|||
int ppc_unit;
|
||||
int ppc_type;
|
||||
|
||||
int ppc_mode; /* chipset current mode */
|
||||
int ppc_avm; /* chipset available modes */
|
||||
|
||||
#define ppc_base ppc_link.base
|
||||
#define ppc_mode ppc_link.mode
|
||||
#define ppc_epp ppc_link.epp_protocol
|
||||
#define ppc_irq ppc_link.id_irq
|
||||
#define ppc_subm ppc_link.submicroseq
|
||||
|
||||
unsigned char ppc_flags;
|
||||
|
||||
struct ppb_link ppc_link;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset errors. XXX
|
||||
*/
|
||||
#define PPC_ENOPORT 9
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset registers.
|
||||
*/
|
||||
|
|
@ -74,12 +74,12 @@ struct ppc_data {
|
|||
#define PPC_ECP_FIFO 0x400 /* ECP fifo register */
|
||||
#define PPC_ECP_ECR 0x402 /* ECP extended control register */
|
||||
|
||||
#define r_dtr(ppc) inb((ppc)->ppc_base + PPC_SPP_DTR)
|
||||
#define r_str(ppc) inb((ppc)->ppc_base + PPC_SPP_STR)
|
||||
#define r_ctr(ppc) inb((ppc)->ppc_base + PPC_SPP_CTR)
|
||||
#define r_epp(ppc) inb((ppc)->ppc_base + PPC_EPP_DATA)
|
||||
#define r_ecr(ppc) inb((ppc)->ppc_base + PPC_ECP_ECR)
|
||||
#define r_fifo(ppc) inb((ppc)->ppc_base + PPC_ECP_FIFO)
|
||||
#define r_dtr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_DTR))
|
||||
#define r_str(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_STR))
|
||||
#define r_ctr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_CTR))
|
||||
#define r_epp(ppc) ((char)inb((ppc)->ppc_base + PPC_EPP_DATA))
|
||||
#define r_ecr(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_ECR))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_FIFO))
|
||||
|
||||
#define w_dtr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_DTR, byte)
|
||||
#define w_str(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_STR, byte)
|
||||
|
|
@ -111,7 +111,7 @@ struct ppc_data {
|
|||
#define PC873_SID 0x08
|
||||
|
||||
/*
|
||||
* Register defines for the SMC FDC37C66xGT parts.
|
||||
* Register defines for the SMC FDC37C66xGT parts
|
||||
*/
|
||||
|
||||
/* Init codes */
|
||||
|
|
@ -124,9 +124,9 @@ struct ppc_data {
|
|||
|
||||
/* Bits */
|
||||
#define SMC_CR1_ADDR 0x3 /* bit 0 and 1 */
|
||||
#define SMC_CR1_MODE 0x8 /* bit 3 */
|
||||
#define SMC_CR1_MODE (1<<3) /* bit 3 */
|
||||
#define SMC_CR4_EMODE 0x3 /* bits 0 and 1 */
|
||||
#define SMC_CR4_EPPTYPE 0x40 /* bit 6 */
|
||||
#define SMC_CR4_EPPTYPE (1<<6) /* bit 6 */
|
||||
|
||||
/* Extended modes */
|
||||
#define SMC_SPP 0x0 /* SPP */
|
||||
|
|
@ -134,5 +134,34 @@ struct ppc_data {
|
|||
#define SMC_ECP 0x2 /* ECP */
|
||||
#define SMC_ECPEPP 0x3 /* ECP and EPP */
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Register defines for the Winbond W83877F parts
|
||||
*/
|
||||
|
||||
#define WINB_W83877F_ID 0xa
|
||||
#define WINB_W83877AF_ID 0xb
|
||||
|
||||
/* Configuration bits */
|
||||
#define WINB_HEFERE (1<<5) /* CROC bit 5 */
|
||||
#define WINB_HEFRAS (1<<0) /* CR16 bit 0 */
|
||||
|
||||
#define WINB_PNPCVS (1<<2) /* CR16 bit 2 */
|
||||
#define WINB_CHIPID 0xf /* CR9 bits 0-3 */
|
||||
|
||||
#define WINB_PRTMODS0 (1<<2) /* CR0 bit 2 */
|
||||
#define WINB_PRTMODS1 (1<<3) /* CR0 bit 3 */
|
||||
#define WINB_PRTMODS2 (1<<7) /* CR9 bit 7 */
|
||||
|
||||
/* W83877F modes: CR9/bit7 | CR0/bit3 | CR0/bit2 */
|
||||
#define WINB_W83757 0x0
|
||||
#define WINB_EXTFDC 0x4
|
||||
#define WINB_EXTADP 0x8
|
||||
#define WINB_EXT2FDD 0xc
|
||||
#define WINB_JOYSTICK 0x80
|
||||
|
||||
#define WINB_PARALLEL 0x80
|
||||
#define WINB_EPP_SPP 0x4
|
||||
#define WINB_ECP 0x8
|
||||
#define WINB_ECP_EPP 0xc
|
||||
|
||||
#endif
|
||||
|
|
|
|||
726
sys/isa/ppc.c
726
sys/isa/ppc.c
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 1997 Nicolas Souchu
|
||||
* Copyright (c) 1997, 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppc.c,v 1.2 1997/09/01 02:08:41 bde Exp $
|
||||
* $Id: ppc.c,v 1.3 1998/04/17 22:36:37 des Exp $
|
||||
*
|
||||
*/
|
||||
#include "ppc.h"
|
||||
|
|
@ -44,6 +44,8 @@
|
|||
#include <i386/isa/isa_device.h>
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
|
||||
#include <i386/isa/ppcreg.h>
|
||||
|
||||
static int ppcprobe(struct isa_device *);
|
||||
|
|
@ -57,14 +59,26 @@ static struct ppc_data *ppcdata[NPPC];
|
|||
static int nppc = 0;
|
||||
|
||||
static char *ppc_types[] = {
|
||||
"SMC", "SMC FDC37C665GT", "SMC FDC37C666GT",
|
||||
"NatSemi", "PC87332", "PC87306",
|
||||
"Intel 82091AA", "Generic", 0
|
||||
"SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306",
|
||||
"82091AA", "Generic", "W83877F", "W83877AF", "Winbond", 0
|
||||
};
|
||||
|
||||
/* list of available modes */
|
||||
static char *ppc_avms[] = {
|
||||
"COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only",
|
||||
"EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only",
|
||||
"ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP",
|
||||
"ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0
|
||||
};
|
||||
|
||||
/* list of current executing modes
|
||||
* Note that few modes do not actually exist.
|
||||
*/
|
||||
static char *ppc_modes[] = {
|
||||
"AUTODETECT", "NIBBLE", "PS/2", "EPP", "ECP+EPP", "ECP+PS/2", "ECP",
|
||||
"UNKNOWN", 0
|
||||
"COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP",
|
||||
"EPP", "EPP", "EPP", "ECP",
|
||||
"ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP",
|
||||
"ECP+EPP", "ECP+EPP", "ECP+EPP", 0
|
||||
};
|
||||
|
||||
static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 };
|
||||
|
|
@ -110,12 +124,19 @@ static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); }
|
|||
static void ppc_reset_epp_timeout(int);
|
||||
static void ppc_ecp_sync(int);
|
||||
|
||||
static int ppc_exec_microseq(int, struct ppb_microseq *, int *);
|
||||
static int ppc_generic_setmode(int, int);
|
||||
|
||||
static struct ppb_adapter ppc_adapter = {
|
||||
|
||||
0, /* no intr handler, filled by chipset dependent code */
|
||||
|
||||
ppc_reset_epp_timeout, ppc_ecp_sync,
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_generic_setmode,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
|
||||
|
|
@ -143,8 +164,8 @@ ppc_ecp_sync(int unit) {
|
|||
DELAY(100);
|
||||
}
|
||||
|
||||
printf("ppc: ECP sync failed as data still " \
|
||||
"present in FIFO.\n");
|
||||
printf("ppc%d: ECP sync failed as data still " \
|
||||
"present in FIFO.\n", unit);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -158,6 +179,35 @@ ppcintr(int unit)
|
|||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ppc_ecp_config(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (chipset_mode & PPB_EPP)
|
||||
/* select EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
else if (chipset_mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
else
|
||||
/* keep ECP mode alone, default for NIBBLE */
|
||||
w_ecr(ppc, 0x70);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_detect_port(struct ppc_data *ppc)
|
||||
{
|
||||
|
||||
w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */
|
||||
w_dtr(ppc, 0xaa);
|
||||
if (r_dtr(ppc) != (char) 0xaa)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_pc873xx_detect
|
||||
*
|
||||
|
|
@ -170,11 +220,11 @@ static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0};
|
|||
static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0};
|
||||
|
||||
static int
|
||||
ppc_pc873xx_detect(struct ppc_data *ppc)
|
||||
ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */
|
||||
{
|
||||
static int index = 0;
|
||||
int base, idport;
|
||||
int val, mode;
|
||||
int val;
|
||||
|
||||
while ((idport = pc873xx_basetab[index++])) {
|
||||
|
||||
|
|
@ -235,7 +285,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
printf("PC873xx locked\n");
|
||||
|
||||
/* work out what mode we're in */
|
||||
mode = PPB_NIBBLE; /* worst case */
|
||||
ppc->ppc_avm |= PPB_NIBBLE; /* worst case */
|
||||
|
||||
outb(idport, PC873_PCR);
|
||||
val = inb(idport + 1);
|
||||
|
|
@ -243,10 +293,10 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport, PC873_PTR);
|
||||
val = inb(idport + 1);
|
||||
if (!(val & PC873_EPPRDIR)) {
|
||||
mode = PPB_EPP; /* As we would have done it anwyay */
|
||||
ppc->ppc_avm |= PPB_EPP; /* As we would have done it anwyay */
|
||||
}
|
||||
} else if ((val & PC873_ECPEN) && (val & PC873_ECPCLK)) {
|
||||
mode = PPB_PS2; /* tolerable alternative */
|
||||
ppc->ppc_avm |= PPB_PS2; /* tolerable alternative */
|
||||
}
|
||||
} else {
|
||||
if (bootverbose)
|
||||
|
|
@ -299,7 +349,7 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport + 1, val);
|
||||
|
||||
/* we are an EPP-32 port */
|
||||
mode = PPB_EPP;
|
||||
ppc->ppc_avm |= PPB_EPP;
|
||||
} else {
|
||||
if (bootverbose)
|
||||
printf("ECP\n");
|
||||
|
|
@ -309,44 +359,21 @@ ppc_pc873xx_detect(struct ppc_data *ppc)
|
|||
outb(idport + 1, inb(idport + 1) | PC873_ECPEN | PC873_ECPCLK);
|
||||
|
||||
/* we look like a PS/2 port */
|
||||
mode = PPB_PS2;
|
||||
ppc->ppc_avm |= PPB_PS2;
|
||||
}
|
||||
}
|
||||
return(mode);
|
||||
|
||||
return(chipset_mode);
|
||||
}
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_detect_ps2(struct ppc_data *ppc)
|
||||
ppc_check_epp_timeout(struct ppc_data *ppc)
|
||||
{
|
||||
char save_control, r;
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
|
||||
save_control = r_ctr(ppc);
|
||||
|
||||
/* Try PS/2 mode */
|
||||
w_ctr(ppc, 0xec);
|
||||
w_dtr(ppc, 0x55);
|
||||
|
||||
/* needed if in ECP mode */
|
||||
if (ppc->ppc_mode == PPB_ECP)
|
||||
w_ctr(ppc, PCD | 0xec);
|
||||
r = r_dtr(ppc);
|
||||
|
||||
if (r != (char) 0xff) {
|
||||
if (r != (char) 0x55)
|
||||
return 0;
|
||||
|
||||
w_dtr(ppc, 0xaa);
|
||||
r = r_dtr(ppc);
|
||||
if (r != (char) 0xaa)
|
||||
return 0;
|
||||
|
||||
return (PPB_NIBBLE);
|
||||
} else
|
||||
w_ctr(ppc, save_control);
|
||||
|
||||
return (PPB_PS2);
|
||||
return (!(r_str(ppc) & TIMEOUT));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -355,11 +382,10 @@ ppc_detect_ps2(struct ppc_data *ppc)
|
|||
* SMC FDC37C66xGT configuration.
|
||||
*/
|
||||
static int
|
||||
ppc_smc37c66xgt_detect(struct ppc_data *ppc, int mode)
|
||||
ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
int s, i;
|
||||
char r;
|
||||
int retry = 0; /* boolean */
|
||||
int type = -1;
|
||||
int csr = SMC66x_CSR; /* initial value is 0x3F0 */
|
||||
|
||||
|
|
@ -404,7 +430,7 @@ config:
|
|||
* If chipset not found, do not continue.
|
||||
*/
|
||||
if (type == -1)
|
||||
return (0);
|
||||
return (-1);
|
||||
|
||||
/* select CR1 */
|
||||
outb(csr, 0x1);
|
||||
|
|
@ -412,65 +438,72 @@ config:
|
|||
/* read the port's address: bits 0 and 1 of CR1 */
|
||||
r = inb(cio) & SMC_CR1_ADDR;
|
||||
if (port_address[r] != ppc->ppc_base)
|
||||
return (0);
|
||||
return (-1);
|
||||
|
||||
ppc->ppc_type = type;
|
||||
|
||||
/*
|
||||
* CR1 and CR4 registers bits 3 and 0/1 for mode configuration
|
||||
* If SPP mode is detected, try to set ECP+EPP mode end retry
|
||||
* detection to verify.
|
||||
* If SPP mode is detected, try to set ECP+EPP mode
|
||||
*/
|
||||
|
||||
retry:
|
||||
/* select CR1 register */
|
||||
if (bootverbose) {
|
||||
outb(csr, 0x1);
|
||||
printf("SMC registers CR1=0x%x", ppc->ppc_unit,
|
||||
inb(cio) & 0xff);
|
||||
|
||||
outb(csr, 0x4);
|
||||
printf(" CR4=0x%x", inb(cio) & 0xff);
|
||||
}
|
||||
|
||||
/* select CR1 */
|
||||
outb(csr, 0x1);
|
||||
|
||||
if (!mode) {
|
||||
if (!chipset_mode) {
|
||||
/* autodetect mode */
|
||||
|
||||
/* 666GT chipset is hardwired to an extended mode */
|
||||
if (type == SMC_37C666GT)
|
||||
mode = PPB_ECP_EPP;
|
||||
/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
|
||||
if (type == SMC_37C666GT) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
|
||||
else if ((inb(cio) & SMC_CR1_MODE) == 0) {
|
||||
} else
|
||||
if ((inb(cio) & SMC_CR1_MODE) == 0) {
|
||||
/* already in extended parallel port mode, read CR4 */
|
||||
outb(csr, 0x4);
|
||||
r = (inb(cio) & SMC_CR4_EMODE);
|
||||
|
||||
switch (r) {
|
||||
case SMC_SPP:
|
||||
/* let's detect NIBBLE or PS/2 later */
|
||||
ppc->ppc_avm |= PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_EPPSPP:
|
||||
mode = PPB_EPP;
|
||||
ppc->ppc_avm |= PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_ECP:
|
||||
/*
|
||||
* Yet, don't know what to do with it! XXX
|
||||
* So, consider ECP mode as PS/2.
|
||||
* (see configuration later).
|
||||
*/
|
||||
mode = PPB_ECP;
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case SMC_ECPEPP:
|
||||
mode = PPB_ECP_EPP;
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* not an extended port mode */
|
||||
ppc->ppc_avm |= PPB_SPP;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* mode forced */
|
||||
|
||||
/* 666GT chipset is hardwired to an extended mode */
|
||||
/* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */
|
||||
if (type == SMC_37C666GT)
|
||||
goto end_detect;
|
||||
|
||||
r = inb(cio);
|
||||
if (mode == PPB_NIBBLE || mode == PPB_PS2) {
|
||||
/* do not use ECP when the mode is forced to SPP */
|
||||
if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) {
|
||||
/* do not use ECP when the mode is not forced to */
|
||||
outb(cio, r | SMC_CR1_MODE);
|
||||
} else {
|
||||
/* an extended mode is selected */
|
||||
|
|
@ -480,30 +513,26 @@ retry:
|
|||
outb(csr, 0x4);
|
||||
r = inb(cio) & ~SMC_CR4_EMODE;
|
||||
|
||||
switch (mode) {
|
||||
case PPB_EPP:
|
||||
if (chipset_mode & PPB_ECP) {
|
||||
if (chipset_mode & PPB_EPP) {
|
||||
outb(cio, r | SMC_ECPEPP);
|
||||
} else {
|
||||
outb(cio, r | SMC_ECP);
|
||||
}
|
||||
} else {
|
||||
/* PPB_EPP is set */
|
||||
outb(cio, r | SMC_EPPSPP);
|
||||
break;
|
||||
|
||||
case PPB_ECP:
|
||||
case PPB_ECP_PS2:
|
||||
outb(cio, r | SMC_ECP);
|
||||
break;
|
||||
|
||||
case PPB_ECP_EPP:
|
||||
outb(cio, r | SMC_ECPEPP);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("ppc: unknown mode (%d)\n",
|
||||
mode);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
end_detect:
|
||||
if (PPB_IS_EPP(mode)) {
|
||||
|
||||
if (bootverbose)
|
||||
printf ("\n");
|
||||
|
||||
if (chipset_mode & PPB_EPP) {
|
||||
/* select CR4 */
|
||||
outb(csr, 0x4);
|
||||
r = inb(cio);
|
||||
|
|
@ -511,11 +540,9 @@ end_detect:
|
|||
/*
|
||||
* Set the EPP protocol...
|
||||
* Low=EPP 1.9 (1284 standard) and High=EPP 1.7
|
||||
* ...then check the result.
|
||||
*/
|
||||
if (ppc->ppc_epp == EPP_1_9)
|
||||
outb(cio, (r & ~SMC_CR4_EPPTYPE));
|
||||
|
||||
else
|
||||
outb(cio, (r | SMC_CR4_EPPTYPE));
|
||||
}
|
||||
|
|
@ -523,86 +550,214 @@ end_detect:
|
|||
/* end config mode */
|
||||
outb(csr, 0xaa);
|
||||
|
||||
/*
|
||||
* Write 100 to the mode bits and disable DMA, enable intr.
|
||||
*/
|
||||
if (mode == PPB_ECP_EPP)
|
||||
w_ecr(ppc, 0x80);
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
/*
|
||||
* Write 001 to the mode bits and disable DMA, enable intr.
|
||||
*/
|
||||
if (mode == PPB_ECP)
|
||||
w_ecr(ppc, 0x20);
|
||||
|
||||
if (PPB_IS_EPP(mode)) {
|
||||
/*
|
||||
* Try to reset EPP timeout bit.
|
||||
* If it fails, try PS/2 and NIBBLE modes.
|
||||
*/
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT))
|
||||
return (mode);
|
||||
} else {
|
||||
if (mode)
|
||||
return (mode);
|
||||
}
|
||||
|
||||
/* detect PS/2 or NIBBLE mode */
|
||||
return (ppc_detect_ps2(ppc));
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Winbond W83877F stuff
|
||||
*
|
||||
* EFER: extended function enable register
|
||||
* EFIR: extended function index register
|
||||
* EFDR: extended function data register
|
||||
*/
|
||||
#define efir ((efer == 0x250) ? 0x251 : 0x3f0)
|
||||
#define efdr ((efer == 0x250) ? 0x252 : 0x3f1)
|
||||
|
||||
static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 };
|
||||
static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 };
|
||||
static int w83877f_keyiter[] = { 1, 2, 2, 1 };
|
||||
static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 };
|
||||
|
||||
static int
|
||||
ppc_check_ecpepp_timeout(struct ppc_data *ppc)
|
||||
ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
char r;
|
||||
int i, j, efer, base;
|
||||
unsigned char r, hefere, hefras;
|
||||
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
for (i = 0; i < 4; i ++) {
|
||||
/* first try to enable configuration registers */
|
||||
efer = w83877f_efers[i];
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT)) {
|
||||
return (PPB_ECP_EPP);
|
||||
/* write the key to the EFER */
|
||||
for (j = 0; j < w83877f_keyiter[i]; j ++)
|
||||
outb (efer, w83877f_keys[i]);
|
||||
|
||||
/* then check HEFERE and HEFRAS bits */
|
||||
outb (efir, 0x0c);
|
||||
hefere = inb(efdr) & WINB_HEFERE;
|
||||
|
||||
outb (efir, 0x16);
|
||||
hefras = inb(efdr) & WINB_HEFRAS;
|
||||
|
||||
/*
|
||||
* HEFRAS HEFERE
|
||||
* 0 1 write 89h to 250h (power-on default)
|
||||
* 1 0 write 86h twice to 3f0h
|
||||
* 1 1 write 87h twice to 3f0h
|
||||
* 0 0 write 88h to 250h
|
||||
*/
|
||||
if ((hefere | hefras) == w83877f_hefs[i])
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* If EPP timeout bit is not reset, DON'T use EPP */
|
||||
w_ecr(ppc, 0x20);
|
||||
return (-1); /* failed */
|
||||
|
||||
return (PPB_ECP_PS2);
|
||||
found:
|
||||
/* check base port address - read from CR23 */
|
||||
outb(efir, 0x23);
|
||||
if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */
|
||||
return (-1);
|
||||
|
||||
/* read CHIP ID from CR9/bits0-3 */
|
||||
outb(efir, 0x9);
|
||||
|
||||
switch (inb(efdr) & WINB_CHIPID) {
|
||||
case WINB_W83877F_ID:
|
||||
ppc->ppc_type = WINB_W83877F;
|
||||
break;
|
||||
|
||||
case WINB_W83877AF_ID:
|
||||
ppc->ppc_type = WINB_W83877AF;
|
||||
break;
|
||||
|
||||
default:
|
||||
ppc->ppc_type = WINB_UNKNOWN;
|
||||
}
|
||||
|
||||
if (bootverbose) {
|
||||
/* dump of registers */
|
||||
printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]);
|
||||
for (i = 0; i <= 0xd; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
for (i = 0x10; i <= 0x17; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
outb(efir, 0x1e);
|
||||
printf("0x%x ", inb(efdr));
|
||||
for (i = 0x20; i <= 0x29; i ++) {
|
||||
outb(efir, i);
|
||||
printf("0x%x ", inb(efdr));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (!chipset_mode) {
|
||||
/* autodetect mode */
|
||||
|
||||
/* select CR0 */
|
||||
outb(efir, 0x0);
|
||||
r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1);
|
||||
|
||||
/* select CR9 */
|
||||
outb(efir, 0x9);
|
||||
r |= (inb(efdr) & WINB_PRTMODS2);
|
||||
|
||||
switch (r) {
|
||||
case WINB_W83757:
|
||||
if (bootverbose)
|
||||
printf("ppc%d: W83757 compatible mode\n",
|
||||
ppc->ppc_unit);
|
||||
return (-1); /* generic or SMC-like */
|
||||
|
||||
case WINB_EXTFDC:
|
||||
case WINB_EXTADP:
|
||||
case WINB_EXT2FDD:
|
||||
case WINB_JOYSTICK:
|
||||
if (bootverbose)
|
||||
printf("ppc%d: not in parallel port mode\n",
|
||||
ppc->ppc_unit);
|
||||
return (-1);
|
||||
|
||||
case (WINB_PARALLEL | WINB_EPP_SPP):
|
||||
ppc->ppc_avm |= PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case (WINB_PARALLEL | WINB_ECP):
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
break;
|
||||
|
||||
case (WINB_PARALLEL | WINB_ECP_EPP):
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP;
|
||||
break;
|
||||
default:
|
||||
printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* mode forced */
|
||||
|
||||
/* select CR9 and set PRTMODS2 bit */
|
||||
outb(efir, 0x9);
|
||||
outb(efdr, inb(efdr) & ~WINB_PRTMODS2);
|
||||
|
||||
/* select CR0 and reset PRTMODSx bits */
|
||||
outb(efir, 0x0);
|
||||
outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1));
|
||||
|
||||
if (chipset_mode & PPB_ECP) {
|
||||
if (chipset_mode & PPB_EPP)
|
||||
outb(efdr, inb(efdr) | WINB_ECP_EPP);
|
||||
else
|
||||
outb(efdr, inb(efdr) | WINB_ECP);
|
||||
} else {
|
||||
/* select EPP_SPP otherwise */
|
||||
outb(efdr, inb(efdr) | WINB_EPP_SPP);
|
||||
}
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
/* exit configuration mode */
|
||||
outb(efer, 0xaa);
|
||||
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_generic_detect
|
||||
*/
|
||||
static int
|
||||
ppc_generic_detect(struct ppc_data *ppc, int mode)
|
||||
ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
{
|
||||
char save_control, r;
|
||||
char save_control;
|
||||
|
||||
/* don't know what to do here */
|
||||
if (mode)
|
||||
return (mode);
|
||||
if (!chipset_mode) {
|
||||
/* first, check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
if ((r_ecr(ppc) & 0xe0) == 0x20) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
|
||||
/* try to reset EPP timeout bit */
|
||||
ppc_reset_epp_timeout(ppc->ppc_unit);
|
||||
/* search for SMC style ECP+EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
}
|
||||
|
||||
r = r_str(ppc);
|
||||
if (!(r & TIMEOUT)) {
|
||||
return (PPB_EPP);
|
||||
}
|
||||
/* try to reset EPP timeout bit */
|
||||
if (ppc_check_epp_timeout(ppc)) {
|
||||
ppc->ppc_avm |= PPB_EPP;
|
||||
|
||||
/* Now check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
r = r_ecr(ppc);
|
||||
if ((r & 0xe0) == 0x20) {
|
||||
/* Search for SMC style EPP+ECP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
/* SMC like chipset found */
|
||||
ppc->ppc_type = SMC_LIKE;
|
||||
}
|
||||
|
||||
return (ppc_check_ecpepp_timeout(ppc));
|
||||
}
|
||||
/* XXX try to detect NIBBLE mode */
|
||||
ppc->ppc_avm |= PPB_NIBBLE;
|
||||
|
||||
return (ppc_detect_ps2(ppc));
|
||||
} else
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, chipset_mode);
|
||||
|
||||
return (chipset_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -611,22 +766,258 @@ ppc_generic_detect(struct ppc_data *ppc, int mode)
|
|||
* mode is the mode suggested at boot
|
||||
*/
|
||||
static int
|
||||
ppc_detect(struct ppc_data *ppc, int mode) {
|
||||
ppc_detect(struct ppc_data *ppc, int chipset_mode) {
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_pc873xx_detect(ppc)))
|
||||
goto end_detect;
|
||||
int i, mode;
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode =
|
||||
ppc_smc37c66xgt_detect(ppc, mode)))
|
||||
goto end_detect;
|
||||
/* list of supported chipsets */
|
||||
int (*chipset_detect[])(struct ppc_data *, int) = {
|
||||
ppc_pc873xx_detect,
|
||||
ppc_smc37c66xgt_detect,
|
||||
ppc_w83877f_detect,
|
||||
ppc_generic_detect,
|
||||
NULL
|
||||
};
|
||||
|
||||
if (!ppc->ppc_mode && (ppc->ppc_mode = ppc_generic_detect(ppc, mode)))
|
||||
goto end_detect;
|
||||
/* if can't find the port and mode not forced return error */
|
||||
if (!ppc_detect_port(ppc) && chipset_mode == 0)
|
||||
return (EIO); /* failed, port not present */
|
||||
|
||||
printf("ppc: port not present at 0x%x.\n", ppc->ppc_base);
|
||||
return (PPC_ENOPORT);
|
||||
/* assume centronics compatible mode is supported */
|
||||
ppc->ppc_avm = PPB_COMPATIBLE;
|
||||
|
||||
end_detect:
|
||||
/* we have to differenciate available chipset modes,
|
||||
* chipset running modes and IEEE-1284 operating modes
|
||||
*
|
||||
* after detection, the port must support running in compatible mode
|
||||
*/
|
||||
for (i=0; chipset_detect[i] != NULL; i++) {
|
||||
if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) {
|
||||
ppc->ppc_mode = mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppc_exec_microseq()
|
||||
*
|
||||
* Execute a microsequence.
|
||||
* Microsequence mechanism is supposed to handle fast I/O operations.
|
||||
*/
|
||||
static int
|
||||
ppc_exec_microseq(int unit, struct ppb_microseq *msq, int *ppbpc)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
struct ppb_microseq *pc;
|
||||
char cc, *p;
|
||||
int i, iter, reg;
|
||||
int error;
|
||||
|
||||
/* static to be reused after few ppc_exec_microseq()/return calls
|
||||
* XXX should be in a context variable shared with ppb level */
|
||||
static int accum;
|
||||
static char *ptr;
|
||||
|
||||
struct ppb_microseq *microseq_stack = 0;
|
||||
struct ppb_microseq *pc_stack = 0;
|
||||
|
||||
/* microsequence registers are equivalent to PC-like port registers */
|
||||
#define r_reg(register,ppc) ((char)inb((ppc)->ppc_base + register))
|
||||
#define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte)
|
||||
|
||||
#define INCR_PC (pc ++) /* increment program counter */
|
||||
#define mi pc /* microinstruction currently executed */
|
||||
|
||||
/* get the state of pc from ppb level of execution */
|
||||
pc = &msq[*ppbpc];
|
||||
|
||||
for (;;) {
|
||||
|
||||
switch (mi->opcode) {
|
||||
case MS_OP_RSET:
|
||||
cc = r_reg(mi->arg[0].i, ppc);
|
||||
cc &= mi->arg[2].c; /* clear mask */
|
||||
cc |= mi->arg[1].c; /* assert mask */
|
||||
w_reg(mi->arg[0].i, ppc, cc);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RASSERT_P:
|
||||
for (i=0; i<mi->arg[0].i; i++)
|
||||
w_reg(mi->arg[1].i, ppc, *ptr++);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RFETCH_P:
|
||||
for (i=0; i<mi->arg[0].i; i++)
|
||||
*ptr++ = r_reg(mi->arg[1].i, ppc) &
|
||||
mi->arg[2].c;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RFETCH:
|
||||
*((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) &
|
||||
mi->arg[1].c;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_RASSERT:
|
||||
|
||||
/* let's suppose the next instr. is the same */
|
||||
prefetch:
|
||||
for (;mi->opcode == MS_OP_RASSERT; INCR_PC)
|
||||
w_reg(mi->arg[0].i, ppc, mi->arg[1].c);
|
||||
|
||||
if (mi->opcode == MS_OP_DELAY) {
|
||||
DELAY(mi->arg[0].i);
|
||||
INCR_PC;
|
||||
goto prefetch;
|
||||
}
|
||||
break;
|
||||
|
||||
case MS_OP_DELAY:
|
||||
DELAY(mi->arg[0].i);
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_TRIG:
|
||||
reg = mi->arg[0].i;
|
||||
iter = mi->arg[1].i;
|
||||
p = (char *)mi->arg[2].p;
|
||||
|
||||
for (i=0; i<iter; i++) {
|
||||
w_reg(reg, ppc, *p++);
|
||||
DELAY((unsigned char)*p++);
|
||||
}
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_SET:
|
||||
accum = mi->arg[0].i;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_DBRA:
|
||||
if (--accum > 0)
|
||||
pc += mi->arg[0].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_BRSET:
|
||||
cc = r_str(ppc);
|
||||
if ((cc & mi->arg[0].c) == mi->arg[0].c)
|
||||
pc += mi->arg[1].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_BRCLEAR:
|
||||
cc = r_str(ppc);
|
||||
if ((cc & mi->arg[0].c) == 0)
|
||||
pc += mi->arg[1].i;
|
||||
else
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_C_CALL:
|
||||
/*
|
||||
* If the C call returns !0 then end the microseq.
|
||||
* The current state of ptr is passed to the C function
|
||||
*/
|
||||
if ((error = mi->arg[0].f(mi->arg[1].p, ptr)))
|
||||
return (error);
|
||||
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_PTR:
|
||||
ptr = (char *)mi->arg[0].p;
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_CALL:
|
||||
if (microseq_stack)
|
||||
panic("%s: too much calls", __FUNCTION__);
|
||||
|
||||
if (mi->arg[0].p) {
|
||||
/* store the state of the actual
|
||||
* microsequence
|
||||
*/
|
||||
microseq_stack = msq;
|
||||
pc_stack = pc;
|
||||
|
||||
/* jump to the new microsequence */
|
||||
msq = (struct ppb_microseq *)mi->arg[0].p;
|
||||
pc = msq;
|
||||
} else
|
||||
INCR_PC;
|
||||
|
||||
break;
|
||||
|
||||
case MS_OP_SUBRET:
|
||||
/* retrieve microseq and pc state before the call */
|
||||
msq = microseq_stack;
|
||||
pc = pc_stack;
|
||||
|
||||
/* reset the stack */
|
||||
microseq_stack = 0;
|
||||
|
||||
/* XXX return code */
|
||||
|
||||
INCR_PC;
|
||||
break;
|
||||
|
||||
case MS_OP_PUT:
|
||||
case MS_OP_GET:
|
||||
case MS_OP_RET:
|
||||
/* can't return to ppb level during the execution
|
||||
* of a submicrosequence */
|
||||
if (microseq_stack)
|
||||
panic("%s: can't return to ppb level",
|
||||
__FUNCTION__);
|
||||
|
||||
/* update pc for ppb level of execution */
|
||||
*ppbpc = (int)(pc - msq);
|
||||
|
||||
/* return to ppb level of execution */
|
||||
return (0);
|
||||
|
||||
default:
|
||||
panic("%s: unknown microsequence opcode 0x%x",
|
||||
__FUNCTION__, mi->opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/* unreached */
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure current operating mode
|
||||
*/
|
||||
static int
|
||||
ppc_generic_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP)
|
||||
ppc_ecp_config(ppc, mode);
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -688,16 +1079,14 @@ ppcprobe(struct isa_device *dvp)
|
|||
ppc->ppc_unit = dvp->id_unit;
|
||||
ppc->ppc_type = GENERIC;
|
||||
|
||||
/* PPB_AUTODETECT is default to allow chipset detection even if
|
||||
* mode is forced by dvp->id_flags (see later, ppc_detect() call) */
|
||||
ppc->ppc_mode = PPB_AUTODETECT;
|
||||
ppc->ppc_epp = (dvp->id_flags & 0x8) >> 3;
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Try and detect if interrupts are working.
|
||||
*/
|
||||
if (!(dvp->id_flags & 0x10))
|
||||
if (!(dvp->id_flags & 0x20))
|
||||
ppc->ppc_irq = (dvp->id_irq);
|
||||
|
||||
ppcdata[ppc->ppc_unit] = ppc;
|
||||
|
|
@ -706,7 +1095,7 @@ ppcprobe(struct isa_device *dvp)
|
|||
/*
|
||||
* Try to detect the chipset and its mode.
|
||||
*/
|
||||
if (ppc_detect(ppc, dvp->id_flags & 0x7))
|
||||
if (ppc_detect(ppc, dvp->id_flags & 0xf))
|
||||
goto error;
|
||||
|
||||
end_probe:
|
||||
|
|
@ -722,6 +1111,7 @@ ppcattach(struct isa_device *isdp)
|
|||
{
|
||||
struct ppc_data *ppc = ppcdata[isdp->id_unit];
|
||||
struct ppb_data *ppbus;
|
||||
char * mode;
|
||||
|
||||
/*
|
||||
* Link the Parallel Port Chipset (adapter) to
|
||||
|
|
@ -730,9 +1120,9 @@ ppcattach(struct isa_device *isdp)
|
|||
ppc->ppc_link.adapter_unit = ppc->ppc_unit;
|
||||
ppc->ppc_link.adapter = &ppc_adapter;
|
||||
|
||||
printf("ppc%d: %s chipset in %s mode%s\n", ppc->ppc_unit,
|
||||
ppc_types[ppc->ppc_type], ppc_modes[ppc->ppc_mode],
|
||||
(PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit,
|
||||
ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm],
|
||||
ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
ppc_epp_protocol[ppc->ppc_epp] : "");
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -23,23 +23,25 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppcreg.h,v 1.1 1997/08/14 14:01:36 msmith Exp $
|
||||
* $Id: ppcreg.h,v 1.2 1997/08/16 14:07:26 msmith Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPC_H
|
||||
#define __PPC_H
|
||||
#ifndef __PPCREG_H
|
||||
#define __PPCREG_H
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset type.
|
||||
*/
|
||||
#define SMC_UNKNOWN 0x0
|
||||
#define SMC_LIKE 0x0
|
||||
#define SMC_37C665GT 0x1
|
||||
#define SMC_37C666GT 0x2
|
||||
#define NS_UNKNOWN 0x3
|
||||
#define NS_PC87332 0x4
|
||||
#define NS_PC87306 0x5
|
||||
#define INTEL_820191AA 0x6
|
||||
#define GENERIC 0x7
|
||||
#define NS_PC87332 0x3
|
||||
#define NS_PC87306 0x4
|
||||
#define INTEL_820191AA 0x5 /* XXX not implemented */
|
||||
#define GENERIC 0x6
|
||||
#define WINB_W83877F 0x7
|
||||
#define WINB_W83877AF 0x8
|
||||
#define WINB_UNKNOWN 0x9
|
||||
|
||||
/*
|
||||
* Generic structure to hold parallel port chipset info.
|
||||
|
|
@ -49,21 +51,19 @@ struct ppc_data {
|
|||
int ppc_unit;
|
||||
int ppc_type;
|
||||
|
||||
int ppc_mode; /* chipset current mode */
|
||||
int ppc_avm; /* chipset available modes */
|
||||
|
||||
#define ppc_base ppc_link.base
|
||||
#define ppc_mode ppc_link.mode
|
||||
#define ppc_epp ppc_link.epp_protocol
|
||||
#define ppc_irq ppc_link.id_irq
|
||||
#define ppc_subm ppc_link.submicroseq
|
||||
|
||||
unsigned char ppc_flags;
|
||||
|
||||
struct ppb_link ppc_link;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset errors. XXX
|
||||
*/
|
||||
#define PPC_ENOPORT 9
|
||||
|
||||
/*
|
||||
* Parallel Port Chipset registers.
|
||||
*/
|
||||
|
|
@ -74,12 +74,12 @@ struct ppc_data {
|
|||
#define PPC_ECP_FIFO 0x400 /* ECP fifo register */
|
||||
#define PPC_ECP_ECR 0x402 /* ECP extended control register */
|
||||
|
||||
#define r_dtr(ppc) inb((ppc)->ppc_base + PPC_SPP_DTR)
|
||||
#define r_str(ppc) inb((ppc)->ppc_base + PPC_SPP_STR)
|
||||
#define r_ctr(ppc) inb((ppc)->ppc_base + PPC_SPP_CTR)
|
||||
#define r_epp(ppc) inb((ppc)->ppc_base + PPC_EPP_DATA)
|
||||
#define r_ecr(ppc) inb((ppc)->ppc_base + PPC_ECP_ECR)
|
||||
#define r_fifo(ppc) inb((ppc)->ppc_base + PPC_ECP_FIFO)
|
||||
#define r_dtr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_DTR))
|
||||
#define r_str(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_STR))
|
||||
#define r_ctr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_CTR))
|
||||
#define r_epp(ppc) ((char)inb((ppc)->ppc_base + PPC_EPP_DATA))
|
||||
#define r_ecr(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_ECR))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_FIFO))
|
||||
|
||||
#define w_dtr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_DTR, byte)
|
||||
#define w_str(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_STR, byte)
|
||||
|
|
@ -111,7 +111,7 @@ struct ppc_data {
|
|||
#define PC873_SID 0x08
|
||||
|
||||
/*
|
||||
* Register defines for the SMC FDC37C66xGT parts.
|
||||
* Register defines for the SMC FDC37C66xGT parts
|
||||
*/
|
||||
|
||||
/* Init codes */
|
||||
|
|
@ -124,9 +124,9 @@ struct ppc_data {
|
|||
|
||||
/* Bits */
|
||||
#define SMC_CR1_ADDR 0x3 /* bit 0 and 1 */
|
||||
#define SMC_CR1_MODE 0x8 /* bit 3 */
|
||||
#define SMC_CR1_MODE (1<<3) /* bit 3 */
|
||||
#define SMC_CR4_EMODE 0x3 /* bits 0 and 1 */
|
||||
#define SMC_CR4_EPPTYPE 0x40 /* bit 6 */
|
||||
#define SMC_CR4_EPPTYPE (1<<6) /* bit 6 */
|
||||
|
||||
/* Extended modes */
|
||||
#define SMC_SPP 0x0 /* SPP */
|
||||
|
|
@ -134,5 +134,34 @@ struct ppc_data {
|
|||
#define SMC_ECP 0x2 /* ECP */
|
||||
#define SMC_ECPEPP 0x3 /* ECP and EPP */
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Register defines for the Winbond W83877F parts
|
||||
*/
|
||||
|
||||
#define WINB_W83877F_ID 0xa
|
||||
#define WINB_W83877AF_ID 0xb
|
||||
|
||||
/* Configuration bits */
|
||||
#define WINB_HEFERE (1<<5) /* CROC bit 5 */
|
||||
#define WINB_HEFRAS (1<<0) /* CR16 bit 0 */
|
||||
|
||||
#define WINB_PNPCVS (1<<2) /* CR16 bit 2 */
|
||||
#define WINB_CHIPID 0xf /* CR9 bits 0-3 */
|
||||
|
||||
#define WINB_PRTMODS0 (1<<2) /* CR0 bit 2 */
|
||||
#define WINB_PRTMODS1 (1<<3) /* CR0 bit 3 */
|
||||
#define WINB_PRTMODS2 (1<<7) /* CR9 bit 7 */
|
||||
|
||||
/* W83877F modes: CR9/bit7 | CR0/bit3 | CR0/bit2 */
|
||||
#define WINB_W83757 0x0
|
||||
#define WINB_EXTFDC 0x4
|
||||
#define WINB_EXTADP 0x8
|
||||
#define WINB_EXT2FDD 0xc
|
||||
#define WINB_JOYSTICK 0x80
|
||||
|
||||
#define WINB_PARALLEL 0x80
|
||||
#define WINB_EPP_SPP 0x4
|
||||
#define WINB_ECP 0x8
|
||||
#define WINB_ECP_EPP 0xc
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue